2017-02-27 7 views
0

J'ai essayé d'implémenter la méthode suivante pour supprimer les entrées doubles dans un tableau de dictionnaires en comparant leurs clés spécifiques. Cependant, cette méthode d'extension ne fonctionne pas en raison de l'erreur:Extension pour les séquences de dictionnaires où les valeurs sont Equatable

Binary operator == cannot be applied to two 'Equatable' operands

Ce sont évidemment même type et assimilables (Iterator.Element.Value), alors pourquoi ça ne marche pas? Je vois qu'il traite Equatable comme un type spécifique, pas une contrainte. Je ne pouvais pas le faire fonctionner avec un type générique ou en écrivant where Iterator.Element == [String: Any], Iterator.Element.Value: Equatable.

Est-ce que vous avez des indices pour résoudre ce problème?

extension Sequence where Iterator.Element == [String: Equatable] { 
    public func removeDoubles(byKey uniqueKey: String) -> [Iterator.Element] { 
     var uniqueValues: [Iterator.Element.Value] = [] 
     var noDoubles: [Iterator.Element] = [] 
     for item in self { 
      if let itemValue = item[uniqueKey] { 
       if (uniqueValues.contains { element in 
        return itemValue == element 
       }) { 
        uniqueValues.append(itemValue) 
        noDoubles.append(item) 
       } 
      } 
     } 
     return noDoubles 
    } 
} 

Répondre

0

A [String: Equatable] est une cartographie de chaînes à tout Type assimilables. Il n'y a aucune promesse que chaque valeur soit le même type équivalent. Cela dit, il n'est pas vraiment possible de créer un tel dictionnaire (puisque Equatable a un type associé), cette extension ne peut donc s'appliquer à aucun type réel dans Swift. (Le fait que vous ne receviez pas d'erreur ici est un bogue dans le compilateur.)

La fonctionnalité dont vous avez besoin pour effectuer ce travail est SE-0142, ce qui est accepté, mais pas implémenté. Vous ne pouvez pas actuellement contraindre une extension basée sur des contraintes de type de cette façon.

Il existe plusieurs façons de réaliser ce que vous essayez de faire. Une façon simple est de passer votre fonction d'égalité:

extension Sequence { 
    public func removeDoubles(with equal: (Iterator.Element, Iterator.Element) -> Bool) -> [Iterator.Element] { 
     var noDoubles: [Iterator.Element] = [] 
     for item in self { 
      if !noDoubles.contains(where: { equal($0, item) }) { 
       noDoubles.append(item) 
      } 
     } 
     return noDoubles 
    } 
} 

let noDupes = dict.removeDoubles(with: { $0["name"] == $1["name"] }) 

Ce chiffre est légèrement différent de votre code dans la façon dont il se comporte quand name manque, mais légère tweaks pourrait obtenir ce que vous voulez. Cela dit, la nécessité de cela suggère fortement un modèle de données incorrect. Si vous avez cette séquence de dictionnaires, et que vous essayez de construire une extension à ce sujet, vous avez certainement voulu avoir une séquence de structures. Alors cela devient plus simple. Le point d'un dictionnaire est un mappage arbitraire des clés aux valeurs. Si vous avez un petit ensemble de clés connues qui sont légales, c'est vraiment une structure.

+0

Vous ne savez pas comment SE-0142 aiderait ici, je pense que vous vouliez dire [extensions paramétrées] (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#parameterized-extensions)? :) – Hamish

+0

Je veux dire extensions paramétrées, mais je pensais que SE-0142 fourni. Probablement mal interprété 142. –

+0

Nous vous remercions de votre aide. Le problème est que ce sont tous des JSON et j'ai besoin de fusionner les deux de chacun - un local et un distant, qui vient du serveur. Après la fusion, il est sauvegardé dans les données de base, et il semble que beaucoup de travail excessif pour créer un autre type de structure, puisque ce sont des NSManagedObjects, donc je ne peux pas les utiliser avant de les insérer. Dans le contexte de la mémoire et de les stocker tous et comparer semblait trop pour ce simple objectif aussi, alors j'ai continué avec des tentatives sur cette extension. – Suryu