从NSMutableArray中通过键值删除对象

4
NSMutableArray *array = [NSMutableArray arrayWithObjects:@{@"name":@"Jenny",@"age":@23},@{@"name":@"Daisy",@"age":@27},nil];

是否可能通过字典对象中的键删除对象?

例如,通过年龄= 27删除对象。


你的意思是要删除第二个字典吗? - Zigii Wong
4个回答

8

要从NSArray中筛选对象,请调用filteredArrayUsingPredicate

NSArray *array = @[@{@"name":@"Jenny",@"age":@23},@{@"name":@"Daisy",@"age":@27}];
NSArray *array2 =
  [array filteredArrayUsingPredicate:
   [NSPredicate predicateWithBlock:^BOOL(id obj, NSDictionary *d) {
      return ![[obj valueForKey:@"age"] isEqual:@27];
  }]];

现在array2是我们想要的数组 - 它是第一个没有年龄为27的数组。
顺便说一下,我知道这不是你要求的,但这种情况是切换到Swift的一个极好的理由。它简单得多;这种问题就像对Swift的一次活生生的霓虹广告:
let array = [["name":"Jenny", "age":23],["name":"Daisy", "age":27]]
let array2 = array.filter {$0["age"] != 27}

非常有趣,以前从未在核心数据之外使用过谓词。这是否仍然在底层执行最坏情况下的n次迭代搜索,还是比普通迭代过程更有效? - Mike
@Mike 这只是一个循环。 - matt

4

您可以使用NSPredicate创建一个新的数组,该数组中不包含不需要的条目。 NSPredicate类似于数据库查询,其中输入的NSArray表示数据库,而输出数组是查询的响应。

NSArray *array = @[  @{@"name":@"Jenny",@"age":@23},
                     @{@"name":@"Daisy",@"age":@27}  ];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age != 27"];
NSArray *filtered = [array filteredArrayUsingPredicate:predicate];

NSLog( @"%@", array );
NSLog( @"%@", filtered );

3
我不确定是否有更直接的方法,但一种方法是简单地遍历数组并测试值。在枚举时无法改变数组,意味着您无法在迭代过程中删除对象,因此一种方法是获取与您的条件匹配的对象的索引,如果找到一个,则中断并删除该索引处的项目。类似以下内容:
NSInteger indexToDelete = -1;

for (NSInteger i = 0; i < array.count; i++) {
   NSDictionary *dict = array[i];

   if ([dict[@"age"] integerValue] == 27) {
      indexToDelete = i;
      break;      
   }
}

if (indexToDelete > 0) {
   [array removeObjectAtIndex:indexToDelete];
}

被其他答案中使用的filteredArrayUsingPredicate所吸引,我对性能很感兴趣,并决定使用Xcode的measureBlock功能进行一次并行性能测试。遍历包含1,000个字典的数组,从每个数组中删除与整数值匹配的一个项目,并比较当项目非常接近数组开头、中间和末尾时的情况,两个版本在每种情况下都倾向于在几千分之一秒内完成,谓词过滤器在每种情况下都稍微快一些。(我们说的是大约0.269秒 vs 0.261秒)
考虑到这一点,我认为在任何主要意义上,两者都没有更好的优势,只是取决于个人喜好。不过,我认为filteredArrayUsingPredicate方法更加简洁。这只是一些额外的思考食粮,让我有理由尝试自己的measureBlock功能。 :)

有一些需要考虑的问题:如果输入数组中有多个条目满足 age == 27,该怎么办? - user3386109
非常好的观点,如果是这样,而且你想把它们全部删除,只需删除 break 即可。 - Mike

1
在这种情况下,您需要循环遍历每个项目,并对每个对象进行手动测试,这取决于您处理的数据大小和用例复杂性,可能是可以接受的。或者,如果适用,考虑将数据存储在SQLite数据库中,并针对它进行查询。

1
你只需要确保在枚举时不进行突变。 - Mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接