2010-06-03 37 views
11

Tengo una pregunta sobre Objective-C hoy en día que involucra NSMutableArray. Procedente de un fondo .net/C#, tengo problemas para trabajar con estas cosas.Obtener elementos únicos de NSMutableArray

Digamos que tengo un objeto llamado "Song"

Mi canción tiene 3 propiedades:

  • Título
  • artista
  • Género

Tengo un NSMutableArray o NSArray que contiene todos mis objetos Song.

¿Cómo voy a tratar de 'consultar' mi matriz para obtener una nueva matriz con solo Artistas (únicos) o de Género.

Donde en .net escribirías una consulta LINQ simple con una cláusula DISTINCT, ¿cómo se resolvería esto en Objective-C? Estoy adivinando con predicados, pero estoy luchando por encontrar una solución.

Gracias de antemano.

+3

Bienvenido a 1990 –

Respuesta

12

Según lo que quiere decir con "artistas únicos", hay un par de soluciones diferentes. Si solo desea obtener todos los artistas y no desea que aparezcan más de una vez, simplemente haga [NSSet setWithArray:[songArray valueForKey:@"artist"]]. Si se refiere a que desea establecer una lista de todas las canciones que son la única canción de su artista, es necesario encontrar primero los artistas que lo único que una canción y luego encontrar las canciones de los artistas:

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

Así que decir que tenemos en la matriz - entre los otros - dos canciones de un artista. Luego, según el predicado @ "artist IN% @", los dos aparecen en la matriz songsWithUniqueArtists. Prefiero usar NSMutableDictionary y agregar objetos con claves únicas. – blyabtroi

33

también es posible usar:

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

del mismo modo, si es necesario comparar todo el objeto se puede crear una nueva propiedad de sólo lectura que combina los valores que desee para que coincida con el (a través de un hash o de otro tipo) de forma dinámica y comparar en ese :

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

NOTA: Tenga en cuenta que devuelve los valores únicos para la propiedad especificada, no los objetos en sí. Por lo tanto, será una matriz de valores NSString, no valores de canción.

+1

Muy bonito; tenga en cuenta la advertencia de que valueForKeyPath: @ "@ distinctUnionOfObjects.the_property" no conserva el orden de clasificación. –

+0

Cualquier forma de obtener el valor de la canción en lugar de la cadena – Nitesh

+0

Si desea los distintos objetos, debe usar un conjunto como en la respuesta aceptada. Puede convertir la matriz en un conjunto utilizando el inicializador -setWithArray (o mejor, comience con un conjunto desde el principio si es posible). También puede usar -isEqual y -hash para anular el mecanismo predeterminado para determinar la singularidad del objeto. – Luke

3

Esto puede no ser directamente aplicable pero es una solución para crear un conjunto único de valores ... Supongamos que tiene una matriz NSMutable de eventos que tienen múltiples entradas duplicadas. Esta matriz se llama eventArray. El objeto NSSet se puede utilizar para recortar esa matriz y luego repoblar esa matriz como se muestra a continuación ...

NSSet *uniqueEvents = [NSSet setWithArray:eventArray]; 

[eventArray removeAllObjects]; 

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

He creado un simple API de consulta para Objective-C que hace que este tipo de tarea mucho más fácil. Utilizando el método Linq-to-ObjectiveC distinct, recuperando canciones con artistas únicos implicaría lo siguiente:

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

Esto devuelve una lista de instancias de canciones, cada una con un artista único.

5

O así:

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

filterTags no era única al principio, pero se convierte en único después de la operación.

3

Use NSOrderedSet en lugar de NSSet.

NSOrderedSet *uniqueOrderedSet = [NSOrderedSet setWithArray:itemsArray]; 
[itemsArray removeAllObjects]; 
[itemsArray addObjectsFromArray:[uniqueOrderedSet allObjects]]; 
Cuestiones relacionadas