在字典数组中搜索字符串数组
Searching an Array of Strings in Array of Dictionaries
我有一个组合数组,需要在另一个字典数组中搜索
字典数组如下:
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;
});
数组组合如下:数组命名为
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];
}
}
目前这个解决方案效率低下并且消耗大量内存。
任何帮助将不胜感激。
另请注意,字典中未找到的任何组合都需要从组合数组中删除。
所以我的问题是我想要在内存分配方面搜索名称的最有效方法。以便它使用最少的内存。
使用(NSPredicate*)predicateWithBlock:
方法可能有助于加快搜索速度。
假设你有一个键数组和一个源数组,你想用键数组过滤源数组。
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时间,内存分配少了一点。我建议您将较大的数据源拆分为较小的块以使用较少的内存。
为此,我建议您使用 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 存储您的联系人数据。
这应该可以解决问题:
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];
我可能误解了这个问题,但不会将 NSPredicate
与一组作品一起使用吗?
NSSet *contactsToSearchFor = [NSSet setWithArray:self.arrayOfSearchCombinationsFormed];
NSPredicate *prediate = [NSPredicate predicateWithFormat:@"name IN[cd] %@", contactsToSearchFor];
NSArray *results = [self.listOfAllContacts filteredArrayUsingPredicate:predicate];
我没有在 XCode 中测试过这个,但它应该可以工作。
为什么不实现一个 binary search algorithm
来搜索数组。
下面提供的 link 为您提供了有关如何实施 binary search
的完整详细信息。
我有一个组合数组,需要在另一个字典数组中搜索
字典数组如下:
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;
});
数组组合如下:数组命名为
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];
}
}
目前这个解决方案效率低下并且消耗大量内存。 任何帮助将不胜感激。
另请注意,字典中未找到的任何组合都需要从组合数组中删除。
所以我的问题是我想要在内存分配方面搜索名称的最有效方法。以便它使用最少的内存。
使用(NSPredicate*)predicateWithBlock:
方法可能有助于加快搜索速度。
假设你有一个键数组和一个源数组,你想用键数组过滤源数组。
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时间,内存分配少了一点。我建议您将较大的数据源拆分为较小的块以使用较少的内存。
为此,我建议您使用 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 存储您的联系人数据。
这应该可以解决问题:
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];
我可能误解了这个问题,但不会将 NSPredicate
与一组作品一起使用吗?
NSSet *contactsToSearchFor = [NSSet setWithArray:self.arrayOfSearchCombinationsFormed];
NSPredicate *prediate = [NSPredicate predicateWithFormat:@"name IN[cd] %@", contactsToSearchFor];
NSArray *results = [self.listOfAllContacts filteredArrayUsingPredicate:predicate];
我没有在 XCode 中测试过这个,但它应该可以工作。
为什么不实现一个 binary search algorithm
来搜索数组。
下面提供的 link 为您提供了有关如何实施 binary search
的完整详细信息。