【问题标题】:Search NSArray for value matching value在 NSArray 中搜索值匹配值
【发布时间】:2011-07-10 15:48:33
【问题描述】:

我有一个 objects 的 NSArray,它有一个名为 name 的特定属性(类型 NSString)。
我有第二个 NSArray 的 NSStrings 是 names

我想获取所有objects 的NSArray,其.name 属性与第二个NSArray 中的names 之一匹配。

我该如何快速高效地完成此任务,因为这将经常需要。

【问题讨论】:

  • 使用 for 循环遍历 NSArray,并将匹配的对象(使用 containsObject 找到)添加到 NSMutableArray。

标签: iphone objective-c ipad nsarray


【解决方案1】:

为什么不直接使用谓词来为您做到这一点?:

// For number kind of values:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF = %@", value];
NSArray *results = [array_to_search filteredArrayUsingPredicate:predicate];

// For string kind of values:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", value];
NSArray *results = [array_to_search filteredArrayUsingPredicate:predicate];

// For any object kind of value (yes, you can search objects also):
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", value];
NSArray *results = [array_to_search filteredArrayUsingPredicate:predicate];

【讨论】:

  • 为什么字符串搜索与对象不同? NSStrings 不也是对象吗?
  • 是的,我很确定你可以。 MATCHES 仅用于字符串,您可以为其添加大小写选项 [cd]。
  • 为此 +1。谓词现在也有了predicateWithBlock,更加方便。
  • “任何对象类型的值”的谓词格式不正确。 MATCHES 仅适用于NSStrings。对于通用对象,您应该使用== 运算符进行比较。即:NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF == %@", value];NSArray *results = [array_to_search filteredArrayUsingPredicate:predicate];
【解决方案2】:

使用您当前的数据结构,您只能在 O(n^2) 时间内完成,方法是为第二个数组的每个成员循环第一个数组一次:

NSMutableArray * array = [NSMutableArray array];
for (NSString * name in names) {
    for (MyObject * object in objects) {
        if ([[myObject name] isEqualToString:name]) {
            [array addObject:object];
        }
    }
}

(Stefan 建议的替代方法:遍历对象数组并询问名称数组是否 containsObject: 获取每个对象的名称。)

但是如果这真的需要更快(实际上取决于数组的大小和执行频率一样多),您可以通过引入将第一个数组中的 names 映射到它们的 NSDictionary 来改进它对象。然后每个查找都是 O(1),总时间是 O(n)。 (您必须使该字典始终与对象数组保持同步,这对于合理的访问器并不难。这种技术还具有相同的name 不能出现在多个对象上的约束。)

获得此结果的另一种方法(并且没有最后一个约束)是为您的第二个集合使用 NSSet,然后遍历调用 containsObject: 的对象数组,其中每个对象都位于名称集中。这种技术是否更好取决于您的两个集合的大小是否大致相同,或者一个比另一个大得多。

【讨论】:

  • 为什么不使用 [names containsObject:object.name]?
  • @Stefan H:当然,如果这种思考方式更适合您的头脑。不过还是 n^2。 :)(已编辑)
  • 请注意,仅当您的对象都不包含相同的 name 时,对第一个数组使用 NSDictionary 才有效 - 取决于您的域。除了这个小警告之外,quixoto 是正确的 - 如果不重新设计数据结构,您将无法改进这一点。
【解决方案3】:

这里有一个简单的方法:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", nameToFind];
[listOfItems filteredArrayUsingPredicate:predicate];

【讨论】:

  • 但这只会找到具有单个名称的对象,它们是需要找到的多个名称。 (例如,我想要所有名称为“Joe”、“Bill”等的对象)
  • 所以将谓词更改为 [NSPredicate predicateWithFormat:@"name IN %@", arrayOfNames],使用 KVC 获取您需要的名称数组,例如:[_arrayOfObjects valueForKeyPath:@"name"],这将为您提供一个 NSArray(或在某些情况下设置),您可以将其用作谓词的 IN %@ 参数。
【解决方案4】:

我喜欢用这个方法:

NSIndexSet *indexes = [_items indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
   return ((MyObject *)obj).name isEqualToString:name];
}];

if (indexes.count != 0) {
//extract your objects from the indexSet, and do what you like...
}

【讨论】:

    【解决方案5】:
    NSMutableArray * foundNames = [NSMutableArray array];
    for (MyObject * objectWithName in objectCollection) {
        if ([names containsObject:objectWithName.name]) {
            [foundNames objectWithName];
        }
    }
    

    【讨论】:

      【解决方案6】:

      最有用的方法是:

      filteredArrayUsingPredicate:
      

      indexesOfObjectsPassingTest:
      

      第二个使用代码块,iOS 4.0 之前不可用

      这两者都将比直接迭代更有效。

      这里有一个很好的例子: http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxUsing.html

      【讨论】:

        【解决方案7】:
        NSMutableArray* solutions = [NSMutableArray array];
        
        for (Object* object in objects){
           for (NSString* name in names){
               if ([object.name isEqualToString:name]){
                  [solutions addObject:object];
                  break; // If this doesnt work remove this
               }
           }
        }
        

        【讨论】:

        • 为什么不使用 [names containsObject:object.name]?
        【解决方案8】:
        int count=0;
        
        if (range.location!=NSNotFound)
          {                   
          [searchindex addObject:[NSString stringWithFormat:@"%d",count]];           
          }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-20
          • 1970-01-01
          • 1970-01-01
          • 2014-07-10
          • 2021-09-15
          • 1970-01-01
          相关资源
          最近更新 更多