2013-08-14 2 views
1

Je récupère des données à partir du stockage Core Data en utilisant un NSFetchRequest et stocke ces données dans un array - tout fonctionne très bien. Dans une prochaine étape, je veux trier ce array en utilisant NSSortDescriptors comme ceci:Le bloc NSComparator n'est pas appelé

array = [array sortedArrayUsingDescriptors:[NSArray arrayWithObjects: 
      [NSSortDescriptor sortDescriptorWithKey:@"score" ascending:NO], 
      [NSSortDescriptor sortDescriptorWithKey:@"score" ascending:NO comparator:^NSComparisonResult(id obj1, id obj2) { 
        if ([[[array objectAtIndex:[obj2 integerValue]] valueForKey:@"lessImportantItems"] containsObject:[array objectAtIndex:[obj1 integerValue]]]) { 
         return (NSComparisonResult)NSOrderedAscending; 
        } else { 
         return (NSComparisonResult)NSOrderedDescending; 
        } 
       }], 
      [NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:NO], nil]]; 

Le problème que j'ai est que le NSComparator bloc dans la seconde NSSortDescriptor n'est pas appelé (j'ai essayé de NSLog). Pour donner quelques informations à ma structure de données, voici la section graphique d'objets Core Data pertinents:

http://screencast.com/t/AOY6IdNFWoK

Qu'est-ce que l'application n'est-il compare les éléments les uns aux autres. Dans un premier temps, le gagnant d'une comparaison par paire obtient un incrément de score. Mais aussi je marque une priorité appariée, c'est-à-dire que j'ajoute une relation un-à-plusieurs lessImportantItems entre le gagnant et le perdant. Donc, dans mon tableau, j'ai d'abord essayer de trier par score, puis, lorsque score sont égaux, j'essaie aussi de trier par priorité appariée.

Peut-être que c'est parce que j'utilise score comme comparateur key deux fois de suite? Mais, d'autre part, NSComparator ne permet pas de passer un relationship en tant que key non plus.

Je ne peux pas sembler craquer celui-ci. Quelqu'un a des idées? Ou peut-être que je devrais adopter une approche différente du tri?

+0

Donc le résultat final que vous voulez est pour les articles à trier? Dans n'importe quelle méthode? Ou une variante de la vôtre? – geekchic

+0

Eh bien, c'est comme il dit avec des descripteurs de tri: (1) trier par score, puis (2) si le score est égal, trier par plus important un-à-un, et enfin (3) trier par date créée (sera réaliste pertinent pour les items de la queue, c'est-à-dire ceux qui ont un score égal à 0 - pas encore comparé). Est-ce ce que vous demandiez? – artooras

Répondre

1

Le deuxième descripteur de tri n'a aucun sens pour moi. Il applique le comparateur donné à l'attribut score des objets à comparer. Donc, à l'intérieur du comparateur, obj1, obj2 sont les valeurs de score des objets à comparer. Il semble que vous essayez d'obtenir les objets sous-jacents avec

[array objectAtIndex:[obj1 integerValue]] 
[array objectAtIndex:[obj2 integerValue]] 

mais qui ne peuvent pas travailler. Ainsi, le second descripteur de tri devrait ressembler à

[NSSortDescriptor sortDescriptorWithKey:@"self" ascending:NO 
     comparator:^NSComparisonResult(Item *item1, Item *item2) { 

     // compare item1, item2 ... 
}]; 

Mais le problème suivant se pose: Comment comparer deux objets en fonction de priorité? Votre code fait essentiellement les éléments suivants:

if ([item2 valueForKey:@"lessImportantItems"] containsObject:item1]) { 
    return NSOrderedAscending; 
} else { 
    return NSOrderedDescending; 
} 

Mais ce n'est pas un comparateur approprié:

  • Il ne retourne pas NSOrderedSame si les objets sont égaux (et non « réfléchi »),
  • Pour deux "objets sans rapport" il renverra NSOrderedDescending indépendamment de l'ordre (pas "asymétrique"),
  • il ne détecte pas si item1 est indirectement relat ed à item2 (pas "transitif").

Mais comment trier les "objets sans rapport"? Il n'y a pas de solution unique. Si B et C sont moins importants que A, alors A, B, C et A, C, B sont des solutions valides. Que devrait renvoyer le comparateur lorsqu'on compare B et C?

Donc je pense que cela ne peut pas être réalisé avec un descripteur de tri et vous devez choisir un autre algorithme, par ex. "Topological sorting".

+1

'pas' symétrique '' vous voulez dire 'pas' asymétrique '' – newacct

+0

@newacct: Oups - oui - corrigés. –

+0

Merci Martin, c'est une réponse. J'ai besoin de temps pour digérer et essayer quelques changements. – artooras

0

Si quelqu'un est intéressé, voici comment j'ai réalisé le tri que je recherchais.

J'utilise seulement la première NSSortDescriptor de l'exemple ci-dessus pour obtenir le array trié par score, puis j'ai appelé une autre méthode de tri sur cette array:

array = [array sortedArrayUsingDescriptors:[NSArray arrayWithObjects: 
      [NSSortDescriptor sortDescriptorWithKey:@"score" ascending:NO], nil]; 

array = [self applyMoreImportantPairOrdering:array]; 

Et voici la méthode:

+ (NSArray *)applyMoreImportantPairOrdering:(NSArray *)array { 

    NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array]; 

    [array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 

     if ([[obj valueForKey:@"score"] integerValue] > 0) { 

      NSMutableSet *lessImportantItemsSet = [NSMutableSet setWithSet:[obj valueForKey:@"lessImportantItems"]]; 

      for (int i = idx - 1; i >= 0; i--) { 

       NSManagedObject *objAbove = [array objectAtIndex:i]; 

       if ([[obj valueForKey:@"score"] integerValue] == [[objAbove valueForKey:@"score"] integerValue]) { 

        if ([lessImportantItemsSet containsObject:objAbove]) { 

         NSUInteger idxAbove = [mutableArray indexOfObject:objAbove]; 

         [mutableArray removeObject:obj]; 
         [mutableArray insertObject:obj atIndex:idxAbove]; 
        } 
       } 
      } 
     } 
    }]; 

    return [NSArray arrayWithArray:mutableArray]; 
} 

La raison pour laquelle j'ai besoin du lessImportantItemsSet est parce que quand je déplace (supprimer et insérer) un item dans un array, il perd ses relations lessImportantItems. Cette façon je maintiens la liste/ensemble de moins important item pendant que j'en ai fini avec le item particulier.