从NSMutableArray获取唯一项

14

今天我有一个涉及NSMutableArray的Objective-C问题。作为一个来自.net/c#背景的人,我在处理这些东西时遇到了一些困难。

假设我有一个名为“Song”的对象

我的歌曲有3个属性:

  • Title(标题)
  • Artist(艺术家)
  • Genre(流派)

我有一个NSMutableArray或NSArray,其中包含所有我的Song对象。

如何查询数组以获取仅包含(唯一的)艺术家或流派的新数组。

在.NET中,您会编写一个带有DISTINCT子句的简单LINQ查询,那么在Objective-C中该怎么解决呢?我猜测可以使用谓词,但是我正在努力寻找解决方案。

6个回答

37

你也可以使用:

NSArray *uniqueArtists = [songs valueForKeyPath:@"@distinctUnionOfObjects.artist"];
NSArray *uniqueGenres = [songs valueForKeyPath:@"@distinctUnionOfObjects.genre"];

同样地,如果你需要比较整个对象,你可以创建一个新的只读属性,通过哈希或其他方式动态地组合你想要匹配的值,并在该属性上进行比较:

NSArray *array = [songs valueForKeyPath:@"@distinctUnionOfObjects.hash"];

注意:请记住,此方法返回指定属性的唯一值,而不是对象本身。因此,它将是一个NSString值的数组,而不是Song值。


1
非常好;请注意,valueForKeyPath:@"@distinctUnionOfObjects.the_property" 不会保留排序顺序。 - Robert Altman
有没有办法获取 Song 值而不是字符串? - Nitesh
如果您想获取不同的对象,应该使用一个集合(set),就像被接受的答案中所示。可以使用-setWithArray初始化器将数组转换为集合(set)(或者最好从一开始就使用集合(set))。还可以使用-isEqual和-hash来覆盖默认机制以确定对象的唯一性。 - Luke

13

根据你对“独特艺术家”的理解不同,有几种不同的解决方案。如果你只想获取所有艺术家,并且不希望出现重复,请使用[NSSet setWithArray:[songArray valueForKey:@"artist"]]。如果你的意思是要设置一个列表,其中所有歌曲都是其艺术家唯一的歌曲,则需要先找到只有一首歌曲的艺术家,然后再找到这些艺术家的歌曲:

NSCountedSet *artistsWithCounts = [NSCountedSet setWithArray:[songArray valueForKey:@"artist"]];
NSMutableSet *uniqueArtists = [NSMutableSet set];
for (id artist in artistsWithCounts)
    if ([artistsWithCounts countForObject:artist] == 1])
        [uniqueArtists addObject:artist];
NSPredicate *findUniqueArtists = [NSPredicate predicateWithFormat:@"artist IN %@", uniqueArtists];
NSArray *songsWithUniqueArtists = [songArray filteredArrayUsingPredicate:findUniqueArtists];

假设我们在数组中有两首来自同一位艺术家的歌曲。然后,根据@"artist IN %@"谓词,这两首歌都会出现在songsWithUniqueArtists数组中。我更喜欢使用NSMutableDictionary,并添加具有唯一键的对象。 - blyabtroi

5
或者像这样:
filterTags  = [[NSSet setWithArray:filterTags] allObjects];

filterTags一开始不是唯一的,但在进行操作后变得唯一了。


3

这可能不是直接适用的,但它是创建一组唯一值的解决方案... 假设您有一个NSMutable数组包含多个重复条目。该数组名为eventArray。可以使用NSSet对象来修剪该数组,然后重新填充该数组,如下所示...

NSSet *uniqueEvents = [NSSet setWithArray:eventArray];

[eventArray removeAllObjects];

[eventArray addObjectsFromArray:[uniqueEvents allObjects]];

3
使用NSOrderedSet代替NSSet。
NSOrderedSet *uniqueOrderedSet = [NSOrderedSet setWithArray:itemsArray];
[itemsArray removeAllObjects];
[itemsArray addObjectsFromArray:[uniqueOrderedSet allObjects]];

-2
我为Objective-C创建了一个简单的查询API,使这种任务变得更加容易。使用Linq-to-ObjectiveC distinct方法,检索具有唯一艺术家的歌曲将涉及以下内容:
NSArray* songsWithUniqueArtistists = [input distinct:^id(id song) {
    return [song artist];
}];

这将返回一个歌曲实例列表,每个实例都有唯一的艺术家。


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