23 votes

NSPredicate : Récupérer un de chaque type

Je veux créer un NSFetchRequest pour des objets comme celui-ci :

El Object es Car qui a un attribute color . J'ai quatre voitures :

car1.color = red
car2.color = red
car3.color = blue
car4.color = green

Je veux créer un NSPredicate qui ne sélectionne qu'une seule voiture pour chaque couleur (peu importe laquelle).

Comment puis-je y parvenir ?

En fait, je cherche quelque chose de similaire, comme une DISTINCT en SQL

20voto

nielsbot Points 9551

Données de base fait permettent de récupérer des valeurs distinctes. Apple fournit même un exemple de code ici : http://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/CoreDataSnippets/Articles/fetchExpressions.html


De cette page :

Récupération de valeurs distinctes

Pour récupérer les valeurs uniques d'un attribut particulier dans tous les sites de l'UE. instances d'une entité donnée, vous configurez une requête de récupération avec la méthode setReturnsDistinctResults : (et passez YES comme paramètre). Vous spécifiez également que la récupération doit retourner des dictionnaires plutôt que des objets gérés. ainsi que le nom de la propriété que vous souhaitez récupérer.

Swift 2.0

let context:NSManagedObjectContext! = <#Get the context#>
let entity = NSEntityDescription.entityForName( "<#Entity name#>",  inManagedObjectContext:context )
let request = NSFetchRequest()
request.entity = entity
request.resultType = .DictionaryResultType
request.returnsDistinctResults = true
request.propertiesToFetch = [ "<#Attribute name#>" ]

var objects:[[String:AnyObject]]?
do
{
    try objects = context.executeFetchRequest( request )
}
catch
{
    // handle failed fetch
}

Obj-C

NSManagedObjectContext *context = <#Get the context#>;  

NSEntityDescription *entity = [NSEntityDescription  entityForName:@"<#Entity name#>" inManagedObjectContext:context];  
NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
[request setEntity:entity]; 
[request setResultType:NSDictionaryResultType];
[request setReturnsDistinctResults:YES]; 
[request setPropertiesToFetch:@[@"<#Attribute name#>"]];  

// Execute the fetch. 

NSError *error = nil; 
id requestedValue = nil; 
NSArray *objects = [context executeFetchRequest:request error:&error]; 
if (objects == nil) {
    // Handle the error. 
} 

(Le problème est que les résultats seront renvoyés sous forme de dictionnaires - si vous avez besoin des objets, vous pouvez effectuer une autre recherche pour les obtenir par ID).

14voto

ggrana Points 1645

Avez-vous essayé d'utiliser valueForKeyPath ? Vous pouvez faire quelque chose comme ça dans le tableau que NSPredicate vous fournit.

NSArray* distinctColors = [cars valueForKeyPath:@"@distinctUnionOfObjects.color"];

Il vous rendra les couleurs distinctes que vous avez, je ne sais pas si c'est ce que vous voulez, mais avec les couleurs vous pouvez faire quelque chose comme @Anupdas a dit :

3voto

Dave FN Points 529

Si vous visez iOS 4.0 ou une version ultérieure et que vous n'utilisez pas le magasin SQL de Core-Data, pourquoi ne pas utiliser la méthode suivante predicateWithBlock: ?

Ce qui suit va générer le NSFetchRequest que vous voulez.

- (NSFetchRequest*) fetchRequestForSingleInstanceOfEntity:(NSString*)entityName groupedBy:(NSString*)attributeName
{
  __block NSMutableSet *uniqueAttributes = [NSMutableSet set];

  NSPredicate *filter = [NSPredicate predicateWithBlock:^(id evaluatedObject, NSDictionary *bindings) {
    if( [uniqueAttributes containsObject:[evaluatedObject valueForKey:attributeName]] )
      return NO;

    [uniqueAttributes addObject:[evaluatedObject valueForKey:attributeName]];
    return YES;
  }];

  NSFetchRequest *req = [NSFetchRequest fetchRequestWithEntityName:entityName];
  req.predicate = filter;

  return req;
}

Vous pouvez ensuite créer une nouvelle méthode pour exécuter la recherche et renvoyer les résultats souhaités.

- (NSArray*) fetchOneInstanceOfEntity:(NSString*)entityName groupedBy:(NSString*)attributeName
{
  NSFetchRequest *req = [self fetchRequestForSingleInstanceOfEntity:entityName groupedBy:attributeName];

  // perform fetch
  NSError *fetchError = nil;
  NSArray *fetchResults = [_context executeFetchRequest:req error:&fetchError];

  // fetch results
  if( !fetchResults ) {
    // Handle error ...
    return nil;
  }

  return fetchResults;
}

0voto

Anupdas Points 7644

Cherchez-vous quelque chose comme ceci

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Car"];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"color ==  %@",@"green"]];
[fetchRequest setFetchLimit:1];

NSError *error = nil;
NSArray *fetchedCars = [context executeFetchRequest:fetchRequest error:&error];

Car *car = [fetchedCars lastObject];

if(!car){
    //Handle the error
}

0voto

I Like IOS Points 488

Essayez ceci :

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"Selected_data"
            inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
NSPredicate *predicatecnName = [NSPredicate predicateWithFormat:@"countries contains[cd] %@", Countryid];
NSPredicate *predicateLn = [NSPredicate predicateWithFormat:@"languages contains[cd] %@", languageid];
NSArray *subPredicates = [NSArray arrayWithObjects:predicatecnName, predicateLn, nil];

NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];

[request setPredicate:predicate];
NSMutableArray *sendfd=[[NSMutableArray alloc] init];
NSError *error;
NSArray *array1 = [self.managedObjectContext executeFetchRequest:request error:&error];

if (array1 != nil) {

    for (Selected_data *sld in array1)
    {

        [sendfd addObject:sld.providers];
    }

}
else {

}
return sendfd;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X