Получение уникальных элементов из NSMutableArray
У меня есть вопрос о Objective-C сегодня с участием NSMutableArray. Исходя из фона .net/С#, у меня возникают проблемы с этим.
Скажем, у меня есть объект под названием "Песня"
Моя песня имеет 3 свойства:
- Название
- Исполнитель
- Жанр
У меня есть NSMutableArray или NSArray, в котором хранятся все мои объекты Song.
Как бы я попытался "запросить" мой массив, чтобы получить новый массив только с (уникальными) артистами или жанром.
Где, как и в .net, вы должны написать простой запрос LINQ с предложением DISTINCT, как решить эту проблему в Objective-C? Я догадываюсь с предикатами, но изо всех сил стараюсь найти решение.
Спасибо заранее.
Ответы
Ответ 1
В зависимости от того, что вы подразумеваете под "уникальными художниками", существует несколько различных решений. Если вы просто хотите, чтобы все художники и не хотели появляться больше одного раза, просто сделайте [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];
Ответ 2
Вы также можете использовать:
NSArray *uniqueArtists = [songs valueForKeyPath:@"@distinctUnionOfObjects.artist"];
NSArray *uniqueGenres = [songs valueForKeyPath:@"@distinctUnionOfObjects.genre"];
Аналогично, если вам нужно сравнить весь объект, вы можете создать новое свойство readonly, которое будет сочетать значения, которые вы хотите сопоставить (с помощью хэша или иначе), динамически и сравнить на них:
NSArray *array = [songs valueForKeyPath:@"@distinctUnionOfObjects.hash"];
ПРИМЕЧАНИЕ.. Помните, что это возвращает значения uniques для указанного свойства, а не сами объекты. Таким образом, это будет массив значений NSString, а не значений Song.
Ответ 3
Или вот так:
filterTags = [[NSSet setWithArray:filterTags] allObjects];
filterTags
сначала не был уникальным, но стал уникальным после операции.
Ответ 4
Это может быть неприменимо, но это решение для создания уникального набора значений...
Предположим, что у вас есть NSMutable массив событий с несколькими повторяющимися записями. Этот массив называется eventArray. Объект NSSet можно использовать для обрезки этого массива и затем повторного заполнения массива, как показано ниже.
NSSet *uniqueEvents = [NSSet setWithArray:eventArray];
[eventArray removeAllObjects];
[eventArray addObjectsFromArray:[uniqueEvents allObjects]];
Ответ 5
Используйте NSOrderedSet вместо NSSet.
NSOrderedSet *uniqueOrderedSet = [NSOrderedSet setWithArray:itemsArray];
[itemsArray removeAllObjects];
[itemsArray addObjectsFromArray:[uniqueOrderedSet allObjects]];
Ответ 6
Я создал простой API запросов для Objective-C, который делает эту задачу намного проще. Используя метод Linq-to-ObjectiveC,, поиск песен с уникальными художниками будет включать в себя следующее:
NSArray* songsWithUniqueArtistists = [input distinct:^id(id song) {
return [song artist];
}];
Это возвращает список экземпляров песен, каждый из которых имеет уникальный художник.