在字典数组中搜索字符串数组

Posted

技术标签:

【中文标题】在字典数组中搜索字符串数组【英文标题】:Searching an Array of Strings in Array of Dictionaries 【发布时间】:2015-03-11 07:37:34 【问题描述】:

我有一个组合数组,需要在另一个字典数组中搜索

字典数组如下:

self.listOfAllContacts

(
    name = "William";
    recordId = 541;
,

    name = "Soan";
    recordId = 541;
,

    name = "kamal";
    recordId = 541;
,

    name = "Elisia";
    recordId = 541;
,  

    name = "Ben";
    recordId = 541;
,

    name = "Loki";
    recordId = 541;
,

    name = "Fraser";
    recordId = 541;
);

Array Of Combinations如下:数组命名为

self.arrayOfSearchCombinationsFormed

  <__NSArrayM 0x1702518b0>(
    ABCD,
    JK,
    AND,
    MIKE,
    ELI,
    STEV,
    FRASE,
    WIILIA
    )

工作中的当前代码:

self.filteredContacts = [[NSMutableArray alloc] init];
    NSArray *arrayToTraversed = [[NSArray alloc] initWithArray:self.arrayOfSearchCombinationsFormed];
    for(NSString *combination in arrayToTraversed)
        NSPredicate *predicateInsideLoop = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@", combination];
        NSArray *filteredContactByName = [self.listOfAllContacts filteredArrayUsingPredicate:predicateInsideLoop];
        if([filteredContactByName count]>0)
            [self.filteredContacts addObjectsFromArray:filteredContactByName];
        
        else
            [self.arrayOfSearchCombinationsFormed removeObject:combination];
        
    

目前这种解决方案效率低下并且消耗大量内存。 任何帮助将不胜感激。

还要注意,字典中没有的任何组合都需要从组合数组中删除。

所以我的问题是,我想要在内存分配方面搜索名称的最有效方式。这样它使用最少的内存。

【问题讨论】:

这里的字典和数组大吗?我确实想知道您为什么不将 NSMutableSet 用于过滤的联系人...我假设您只希望每个联系人一次。 字典很大。即大约 10,000 个项目,但数组很小,即最多 50 个项目。而且我无法理解 NSMutableSet 在这里如何帮助我。 一个优化是一旦联系人符合您的规则就从联系人列表中删除,从而减少循环的长度。 我无法删除原始数组,因为我必须在用户交互列表中进一步搜索。 @Harsh 您可以创建原始数组的副本。我认为这是一种优化算法的简单方法,但是当符合规则的联系人数量很少时,它并没有太大帮助。 【参考方案1】:

使用(NSPredicate*)predicateWithBlock: 方法可能有助于加快搜索速度。

假设你有一个keys数组和一个源数组,你想用keys数组过滤源数组。

NSArray *keysArray = @[@"1",@"2",@"3"];    
NSArray *sourceArray = @[@"12",@"2",@"3",@"1",@"2"];

对于sourceArray中的第一个对象@"12",查看keysArray,由于@"12"包含@"1",可以停止过滤,保留两个数组的第一个对象。但是原代码使用@"1"过滤sourceArray,结果是@"12"@"1",每个元素都需要检查。

您可以参考以下代码:

- (void)searchWithBlock:(NSArray*)keysArray

    NSDate *beginDate = [NSDate date];

    NSMutableSet *keySet = [NSMutableSet set];
    NSPredicate *intersectPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) 
        for (NSString *str in keysArray) 
            NSString *name = evaluatedObject[@"name"];
            NSRange r = [name rangeOfString:str options:NSCaseInsensitiveSearch];
            if (r.location != NSNotFound) 
                [keySet addObject:str];
                return true;
            
        
        return false;
    ];

    NSArray *intersect = [self.listOfAllContacts filteredArrayUsingPredicate:intersectPredicate];
    self.filteredContacts = [[NSMutableArray alloc] initWithArray:intersect];

    self.arrayOfSearchCombinationsFormed = [NSMutableArray arrayWithArray:[keySet allObjects]];

    NSDate *endDate = [NSDate date];
    NSTimeInterval interval = [endDate timeIntervalSinceDate:beginDate];
    NSLog(@"interval is %f",interval);

    NSLog(@"intersect %@\n, filtered key array is %@\n", intersect,keySet);

过滤时间大约是原来的1/3,内存分配少了一点。我建议您将较大的数据源拆分为较小的块以使用更少的内存。

【讨论】:

【参考方案2】:

这应该可以解决问题:

NSString *sourceRegexp =
    [NSString stringWithFormat:@".*%@.*", 
        [combinations componentsJoinedByString:@".*|.*"]];

NSPredicate *sourcePredicate =
    [NSPredicate predicateWithFormat:@"name MATCHES[c] %@", sourceRegexp];

NSArray *filteredSource =
    [source filteredArrayUsingPredicate:sourcePredicate];

NSPredicate *combinationsPredicate =
    [NSPredicate predicateWithFormat:
        @"SUBQUERY(%@, $s, $s.name CONTAINS[c] SELF).@count > 0",
        filteredSource];

NSArray *filteredCombinations =
    [combinations filteredArrayUsingPredicate:combinationsPredicate];

【讨论】:

【参考方案3】:

我可能误解了这个问题,但不会将NSPredicate 与一组作品一起使用吗?

NSSet *contactsToSearchFor = [NSSet setWithArray:self.arrayOfSearchCombinationsFormed];
NSPredicate *prediate = [NSPredicate predicateWithFormat:@"name IN[cd] %@", contactsToSearchFor];
NSArray *results = [self.listOfAllContacts filteredArrayUsingPredicate:predicate];

我还没有在 XCode 中测试过这个,但它应该可以工作。

【讨论】:

【参考方案4】:

为什么不实现binary search algorithm 来搜索数组。

下面提供的链接为您提供了有关如何实现binary search 的完整详细信息。

见:http://oleb.net/blog/2013/07/nsarray-binary-search/

【讨论】:

【参考方案5】:

我建议您为此目的使用 swift:它更快并且分配的内存更少。这是 Swift 中的一个解决方案:

func filterContacts(contacts: [Dictionary<String, String>], searchCombinations: [String]) -> [Dictionary<String, String>]
   return contacts.filter  dict in
      let name = dict["name"]!
      for string in searchCombinations
         if name.rangeOfString(string) != nil  return true 
      
      return false
   

如果搜索的持续时间很重要,另一个更复杂的解决方案是使用Suffix Tree 来存储您的联系人数据。

【讨论】:

以上是关于在字典数组中搜索字符串数组的主要内容,如果未能解决你的问题,请参考以下文章

字典数组和字符串的过滤器数组

从位于字典中的数组中删除与搜索词匹配的所有值(字符串)?

检查哪些字典键对应的数组包含某个字符串

Java数组搜索[关闭]

给定一个字符串数组,返回所有的字谜字符串组

从数组中的字典中获取字符串[关闭]