web-dev-qa-db-fra.com

Tri d'un dictionnaire en place par rapport aux clés

J'ai un dictionnaire en C # comme

Dictionary<Person, int>

et je veux trier ce dictionnaire en place en ce qui concerne les clés (un champ dans la classe Person). Comment puis-je le faire? Chaque aide disponible sur Internet est celle de listes sans exemple particulier de tri en place de Dictionary. Toute aide serait très appréciée!

67
SoulReaver

Vous ne pouvez pas trier un Dictionary<TKey, TValue> _ c'est intrinsèquement non ordonné. (Ou plutôt, l'ordre dans lequel les entrées sont extraites est spécifique à l'implémentation. Vous ne devez pas vous fier à ce qu'il fonctionne de la même manière entre les versions, car la commande ne fait pas partie de ses fonctionnalités conçues.)

Vous pouvez utiliser SortedList<TKey, TValue> ou SortedDictionary<TKey, TValue> , tous deux triés par clé (de manière configurable, si vous passez un IEqualityComparer<T> dans le constructeur) - est-ce que cela peut vous être utile?

Faites peu attention au mot "liste" dans le nom SortedList - il reste un dictionnaire dans la mesure où il associe les clés aux valeurs. Il est mis en œuvre en utilisant une liste en interne, de manière efficace - donc au lieu de rechercher par code de hachage, il effectue une recherche binaire. De même, SortedDictionary est basé sur des recherches binaires, mais via une arborescence plutôt qu'une liste.

141
Jon Skeet

Essayez d'utiliser SortedDictionary

24
Chris O

La réponse correcte est déjà indiquée (utilisez simplement SortedDictionary).

Cependant, si par hasard vous avez besoin de conserver votre collection en tant que dictionnaire, il est possible d'accéder aux clés du dictionnaire de manière ordonnée, par exemple en les classant dans une liste, puis en utilisant cette liste pour accéder au dictionnaire. Un exemple...

Dictionary<string, int> dupcheck = new Dictionary<string, int>();

... du code qui remplit "dupcheck", alors ...

if (dupcheck.Count > 0) {
  Console.WriteLine("\ndupcheck (count: {0})\n----", dupcheck.Count);
  var keys_sorted = dupcheck.Keys.ToList();
    keys_sorted.Sort();
  foreach (var k in keys_sorted) {
    Console.WriteLine("{0} = {1}", k, dupcheck[k]);
  }
}

N'oublie pas using System.Linq; pour ça.

10
Steve Greene

De par leur conception, les dictionnaires ne sont pas triables. Si vous avez besoin de cette fonctionnalité dans un dictionnaire, consultez plutôt SortedDictionary.

7
Scott Dorman

Jetez un coup d'œil à SortedDictionary, il y a même une surcharge de constructeur qui vous permet de transmettre votre propre IComparable pour les comparaisons.

4
Dave Downs

Alors que Dictionary est implémenté en tant que table de hachage, SortedDictionary est implémenté en tant qu'arbre rouge-noir.

Si vous ne tirez pas parti de l'ordre de votre algorithme et que vous devez seulement trier les données avant la sortie, tiliser SortedDictionary aurait un impact négatif sur les performances.

Vous pouvez "trier" le dictionnaire comme ceci:

Dictionary<string, int> dictionary = new Dictionary<string, int>();
// algorithm
return new SortedDictionary<string, int>(dictionary);
3
Draex_

En raison de cette réponse élevée de recherche place, je pensais que la solution LINQ OrderBy vaut la peine d'être montrée:

class Person
{
    public Person(string firstname, string lastname)
    {
        FirstName = firstname;
        LastName = lastname;
    }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

static void Main(string[] args)
{
    Dictionary<Person, int> People = new Dictionary<Person, int>();

    People.Add(new Person("John", "Doe"), 1);
    People.Add(new Person("Mary", "Poe"), 2);
    People.Add(new Person("Richard", "Roe"), 3);
    People.Add(new Person("Anne", "Roe"), 4);
    People.Add(new Person("Mark", "Moe"), 5);
    People.Add(new Person("Larry", "Loe"), 6);
    People.Add(new Person("Jane", "Doe"), 7);

    foreach (KeyValuePair<Person, int> person in People.OrderBy(i => i.Key.LastName))
    {
        Debug.WriteLine(person.Key.LastName + ", " + person.Key.FirstName + " - Id: " + person.Value.ToString());
    }
}

Sortie:

Doe, John - Id: 1
Doe, Jane - Id: 7
Loe, Larry - Id: 6
Moe, Mark - Id: 5
Poe, Mary - Id: 2
Roe, Richard - Id: 3
Roe, Anne - Id: 4

Dans cet exemple, il serait judicieux d'utiliser également ThenBy pour les prénoms:

foreach (KeyValuePair<Person, int> person in People.OrderBy(i => i.Key.LastName).ThenBy(i => i.Key.FirstName))

Alors la sortie est:

Doe, Jane - Id: 7
Doe, John - Id: 1
Loe, Larry - Id: 6
Moe, Mark - Id: 5
Poe, Mary - Id: 2
Roe, Anne - Id: 4
Roe, Richard - Id: 3

LINQ propose également les options OrderByDescending et ThenByDescending pour ceux qui en ont besoin.

1
Daniel S. Fowler