2010-06-03 16 views
11

Ho una domanda su Objective-C che coinvolge NSMutableArray. Provenendo da uno sfondo .net/C# sto avendo qualche problema a lavorare con queste cose.Ottenere elementi unici da NSMutableArray

Diciamo che ho un oggetto chiamato "Song"

La mia canzone ha 3 proprietà:

  • Titolo
  • Artista
  • genere

Ho un NSMutableArray o NSArray contiene tutti i miei oggetti Song.

Come dovrei provare a "interrogare" il mio array per ottenere un nuovo array con solo (Unique) Artists o genere.

Dove, come in .net, si scriverebbe una semplice query LINQ con una clausola DISTINCT, come si risolverebbe questo in Objective-C? Sto indovinando con i predicati ma sto lottando per trovare una soluzione.

Grazie in anticipo.

+3

Benvenuti nel 1990 –

risposta

12

A seconda di cosa intendi per "artisti unici", ci sono un paio di soluzioni diverse. Se vuoi solo ottenere tutti gli artisti e non vuoi che vengano visualizzati più di una volta, basta fare [NSSet setWithArray:[songArray valueForKey:@"artist"]]. Se vuoi dire che si desidera impostare un elenco di tutte le canzoni che sono l'unica canzone da loro artista, è necessario trovare prima gli artisti che fanno solo una canzone e poi trovare le canzoni di questi artisti:

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]; 
+0

Quindi diciamo che abbiamo nell'array - tra gli altri - due brani di un artista. Quindi, in base al predicato @ "artist IN% @", tutti e due compaiono nell'array songWithUniqueArtists. Preferisco usare NSMutableDictionary e aggiungere oggetti con chiavi univoche. – blyabtroi

33

si potrebbe anche usare:

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

Allo stesso modo, se avete bisogno di confrontare l'intero oggetto è possibile creare una nuova proprietà di sola lettura che unisce i valori che si desidera abbinare su (tramite un hash o altro) in modo dinamico e confrontare su quella :

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

NOTA: Tenere presente che restituisce i valori univoci per la proprietà specificata, non gli oggetti stessi. Quindi sarà un array di valori NSString, non di Song.

+1

Molto bello; essere consapevoli del problema che valueForKeyPath: @ "distinctUnionOfObjects.the_property" non conserva l'ordinamento. –

+0

Qualsiasi modo per ottenere il valore della song invece della stringa – Nitesh

+0

Se si desidera che gli oggetti distinti si utilizzino un set come nella risposta accettata. È possibile convertire l'array in un set usando l'inizializzatore -setWithArray (o meglio, iniziare con un set dall'inizio, se possibile). È anche possibile utilizzare -isEqual e -hash per sovrascrivere il meccanismo predefinito per determinare l'unicità dell'oggetto. – Luke

3

Questo potrebbe non essere direttamente applicabile ma è una soluzione per creare un insieme univoco di valori ... Si supponga di disporre di un array NSMutable di eventi con più voci duplicate. Questo array è denominato eventArray. L'oggetto NSSet può essere utilizzata per tagliare tale matrice e quindi ripopolare questo array come mostrato di seguito ...

NSSet *uniqueEvents = [NSSet setWithArray:eventArray]; 

[eventArray removeAllObjects]; 

[eventArray addObjectsFromArray:[uniqueEvents allObjects]]; 
-2

Ho creato una semplice API query per Objective-C che rende questo tipo di compito molto più facile. Utilizzando il metodo Linq-to-ObjectiveC distinct, recuperando canzoni con artisti unici comporterebbe la seguente:

NSArray* songsWithUniqueArtistists = [input distinct:^id(id song) { 
    return [song artist]; 
}]; 

Questo restituisce un elenco di istanze di canzoni, ognuno con un artista unico.

5

O come questa:

filterTags = [[NSSet setWithArray:filterTags] allObjects]; 

filterTags non era unico in un primo momento, ma diventa unico dopo l'operazione.

3

Utilizzare NSOrderedSet anziché NSSet.

NSOrderedSet *uniqueOrderedSet = [NSOrderedSet setWithArray:itemsArray]; 
[itemsArray removeAllObjects]; 
[itemsArray addObjectsFromArray:[uniqueOrderedSet allObjects]]; 
Problemi correlati