Vă mulțumim pentru susținere

Cum sortezi un dicționar după valoare?

I often have to sort a dictionary, consisting of keys & values, by value. For example, I have a hash of words and respective frequencies, that I want to order by frequency.

Există un SortedList care este bun pentru o singură valoare (de exemplu, frecvența), pe care vreau să o reintroduc la cuvânt.

SortedDictionary orders by key, not value. Some resort to a custom class, but is there a cleaner way?

0
adăugat editat
În afară de a sorta doar dicționarul (ca în răspunsul acceptat), puteți crea doar un IComparer care face trucul (adevărat că acceptă o cheie pentru a compara, dar cu o cheie, puteți obține o valoare). ;-)
adăugat autor BrainSlugs83

17 răspunsuri

La un nivel înalt, nu ai altă posibilitate decât să mergi prin întregul dicționar și să privești fiecare valoare.

Poate că acest lucru vă ajută: http://bytes.com/forum/thread563638.html Copierea / lipirea de la John Timney:

Dictionary s = new Dictionary();
s.Add("1", "a Item");
s.Add("2", "c Item");
s.Add("3", "b Item");

List> myList = new List>(s);
myList.Sort(
    delegate(KeyValuePair firstPair,
    KeyValuePair nextPair)
    {
        return firstPair.Value.CompareTo(nextPair.Value);
    }
);
0
adăugat
stringnextPair -> string> nextPair stringfirstPair -> string> firstPair
adăugat autor Art
Soluție perfectă non-Linq. Nu inceta niciodata sa ma uimeasca cum oamenii simt nevoia de a folosi Linq chiar si atunci cand nu este absolut necesar sa rezolve problema. Cu C # 3, cred că puteți simplifica de asemenea Sortarea pentru a folosi doar o lambda: myList.Sort ((x, y) => x.Value.CompareTo (y.Value));
adăugat autor RobinHood70

Privind în jur și folosind câteva funcții C # 3.0, putem face acest lucru:

foreach (KeyValuePair item in keywordCounts.OrderBy(key=> key.Value))
{ 
    // do something with item.Key and item.Value
}

Acesta este cel mai curat mod pe care l-am văzut și este similar cu modul Ruby de manipulare hashes.

0
adăugat
Acest lucru a fost la îndemână. Cum poate fi inversat să mergem invers?
adăugat autor Dan Hastings
@AndriusNaru? Evi? Ius: Dacă adăugați elementele rezultate înapoi într-un dicționar, veți distruge comanda, deoarece nu sunt garantate dicționarele să fie comandat în mod particular .
adăugat autor O. R. Mapper
Nu uitați să adăugați spațiul de nume System.Linq atunci când utilizați această sintaxă.
adăugat autor M. Dudley
(pentru elementul KeyValuePair în keywordCounts.OrderBy (key => key.Value) selectați elementul) .ToDictionary (t => t.Key, t => t.Value) un mic plus pentru răspunsul dvs. :) Multumesc, btw :)
adăugat autor Andrius Naruševičius
Am încercat să sortez un dicționar în timp ce adaugă KeyValuePairs la un ComboBox ... acest lucru a funcționat minunat! Mulțumiri!
adăugat autor Jason Down

Utilizare:

using System.Linq.Enumerable;
...
List> myList = aDictionary.ToList();

myList.Sort(
    delegate(KeyValuePair pair1,
    KeyValuePair pair2)
    {
        return pair1.Value.CompareTo(pair2.Value);
    }
);

Since you're targeting .NET 2.0 or above, you can simplify this into lambda syntax -- it's equivalent, but shorter. If you're targeting .NET 2.0 you can only use this syntax if you're using the compiler from Visual Studio 2008 (or above).

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));
0
adăugat
este o linie - Nu aveți nevoie de bretele. poate fi rescrisă ca myList.Sort ((x, y) => x.Value.CompareTo (y.Value));
adăugat autor Arnis Lapsa
Pot să te refer la Skeet stackoverflow.com/a/2705623/41211
adăugat autor GONeale
dar acest răspuns a fost greu de înțeles deoarece nu sunt familiarizați cu cuvântul cheie delegat (poate diferit în vb), n nu este clar unde se întâmplă sortarea deoarece ar trebui fie să executați numărul de element înmulțit cu numărul de articole (nr de elemente pătrat) comparații prin căutarea / compararea fiecărui element cu întregul dicționar pentru fiecare element sau dacă faci doar o comparație între ultimul n ultim, atunci ar trebui să faci asta în mai multe buclă peste colecție, care este motivul pentru care nu am primit-o așa cum este. poate mai multe informații despre locul în care
adăugat autor Erx_VB.NExT.Coder
Cum ar arăta această declarație delegată în metoda de sortare în VB.NET?
adăugat autor Jonas Axelsson
Voi sunteți excesiv de complicați - un dicționar deja implementează IEnumerable , astfel încât să puteți obține o listă sortată astfel: var mySortedList = myDictionary.OrderBy (d => d.Value). ToList ();
adăugat autor BrainSlugs83
Am folosit această soluție (Multumesc!) Dar am fost confuz pentru un minut până când am citit postul lui Michael Stum (și fragmentul de cod de la John Timney) și mi-am dat seama că myList este un obiect secundar, o listă de KeyValuePairs, care este creată din dicționar, și apoi sortate.
adăugat autor Robin Bennett
Știu că sunt doi ani mai târziu ... dar sunt sigur că acest lucru ar putea ajuta pe cineva în locul comentariului anterior: myList.Sort (Funcția (FirstPair As KeyValuePair (String, String), nextPair As KeyValuePair (String, String )) firstPair.Value.CompareTo (nextPair.Value))
adăugat autor sacredfaith
Pentru a sorta în ordine descrescătoare comutați x și y pe compararea: myList.Sort ((x, y) => y.Value.CompareTo (x.Value));
adăugat autor Arturo
Cred că merită observat că acest lucru necesită Linq pentru metoda de extensie ToList.
adăugat autor Ben

Utilizați LINQ:

Dictionary myDict = new Dictionary();
myDict.Add("one", 1);
myDict.Add("four", 4);
myDict.Add("two", 2);
myDict.Add("three", 3);

var sortedDict = from entry in myDict orderby entry.Value ascending select entry;

Acest lucru ar permite, de asemenea, o mare flexibilitate în faptul că puteți selecta topul 10, 20 10% etc. De asemenea, dacă utilizați indexul de frecvență pentru codul type-ahead , puteți include și Începe și cu clauza .

0
adăugat
Ignorați toate sugestiile din .ToDictionary - dicționarele standard nu garantează o ordine de sortare
adăugat autor AlexFoxGill
Pentru cei care folosesc .NET 2.0 - ați încercat să utilizați LINQBridge pentru a umple golurile? albahari.com/nutshell/linqbridge.aspx
adăugat autor jocull
@BorisB. M-am întors în versiunea corectă. Ai fi putut face și tu. Oricine poate edita pentru a face SO un loc mai bun. Pentru toți, ToDictionary nu este un răspuns corect la această problemă, iar răspunsul original de către caryden nu a avut-o. Împreună cu voturi și fără coborâre.
adăugat autor nawfal
Mare răspuns. Și, așa cum am menționat în alte comentarii cu privire la alte răspunsuri, asigurați-vă că includeți "folosind System.Linq;" în partea de sus a fișierului. În caz contrar, veți primi mesaje de eroare oarecum confuze și IntelliSense nu vă ajută.
adăugat autor Mark Meuer
Tipul de returnare trebuie să fie IEnumerable > sau OrderedDictionary . Sau ar trebui să folosiți un SortedDictionary de la început. Pentru un Dictionary simplu, MSDN afirmă clar că "Ordinea în care elementele returnate este nedefinită". Se pare că cea mai recentă editare a lui @ rythos42 este de vină. :)
adăugat autor Boris B.
Cum pot schimba sortDict înapoi într-un Dicționar ? Postat o nouă întrebare despre SO aici:
adăugat autor Kache
Din păcate, acest lucru nu funcționează pe VS2005 din cauza .NET framework 2.0 acolo (nu LINQ). Este bine să aveți și răspunsul lui Bambrick.
adăugat autor Smalcat
Nu sunt sigur dacă funcționează întotdeauna deoarece iterarea peste dicționar nu garantează că KeyValuePairs sunt "trase" în aceeași ordine în care au fost inserate. Ergo, nu contează dacă folosiți comanda în LINQ deoarece Dicționarul poate schimba ordinea elementelor inserate. De obicei, funcționează așa cum era de așteptat, dar nu există GARANȚIE, în special pentru dicționarele mari.
adăugat autor Bozydar Sobczak
Tocmai am folosit o metodă simplă pentru a împiedica acest răspuns împotriva celuilalt răspuns (folosind un Stopwatch () ) și a ieșit cu o creștere de aproape 350% . Patru (!) Lista de membri sortate folosind altă metodă = 0.0039511 secunde; (aceeași) listă cu patru membri sortată folosind metoda LINQ = 0.0130195 secunde.
adăugat autor mbrownnyc
var ordered = dict.OrderBy(x => x.Value);
0
adăugat
@theJerm: nu este adevărat
adăugat autor AlexFoxGill
Folosind cadrul 4.5, tocmai ați verificat că nu necesită o redare în dicționar.
adăugat autor Jagd
Nu sunt sigur de ce această soluție nu este mai populară - probabil pentru că necesită .NET 3.5?
adăugat autor Contango
Pentru că necesită o redare în dicționar, care nu este întotdeauna dreaptă ...
adăugat autor MoonKnight
@Jerm prin punerea elementelor sortate înapoi la un dicționar este ordinea garantată atunci? Ar putea funcționa astăzi, dar nu este garantat.
adăugat autor nawfal
Aceasta este o soluție bună, dar ar trebui să aibă acest drept înainte de sfârșitul semi-colon: .ToDictionary (pair => pair.Key, pair => pair.Value);
adăugat autor theJerm
Prefer acest lucru, curat și simplu. @Gravitas: Sunt de acord, iar versiunea-cadru nu a fost menționată în PO.
adăugat autor Andreas
Nu ar trebui să se vadă în dicționar, deoarece dicționarele nu sunt ordonate. Nu există nicio garanție că KeyValuePairs va rămâne în ordinea dorită.
adăugat autor David DeMar

Niciodată nu ai putea să sortezi un dicționar oricum. Ele nu sunt de fapt ordonate. Garanțiile pentru un dictionar sunt că colecțiile cheie și valori sunt iterabile, iar valorile pot fi extrase prin index sau cheie, dar aici nu există nicio garanție a unei anumite ordini. Prin urmare, va trebui să obțineți o pereche de valori de nume într-o listă.

0
adăugat
@ recursive Orice dicționar ar trebui să obțină acest lucru. Interesant este faptul că răspunsul meu, care este corect, dar incomplet (ar fi putut face ceea ce exemplele mai bune au făcut) este votat sub un răspuns nevalid care ar duce la excepții privind valorile duplicate din dicționarul original (cheile sunt unice, valorile nu sunt garantate a fi)
adăugat autor Roger Willcocks
Un dicționar ordonat ar putea genera o listă de perechi cheie-valoare deși.
adăugat autor recursive
Acesta este răspunsul de mai sus, deoarece Dicționarul nu este indicat. Ea tastează Keys și puteți efectua o operație extrem de rapidă de căutare pe ea.
adăugat autor Paulius Zaliaduonis

Puteți să sortați un Dicționar după valoare și să îl salvați înapoi la el însuși (astfel încât atunci când precizați peste acesta valorile să iasă în ordine):

dict = dict.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);

Sigur, poate că nu este corect, dar funcționează.

0
adăugat
adăugat autor AlexFoxGill
Cred că aceasta va funcționa dacă elementele sunt adăugate în dicționar în același timp și nimic nu este eliminat / modificat. există vreo dovadă că .NET va rearanja elementele din dicționar?
adăugat autor AaA
Ieșirea dicționarului NU este garantată că are o ordine de sortare specială.
adăugat autor Roger Willcocks
Acest "lucru" nu este garantat. Este un detaliu al implementării. Nu trebuie să lucrați alteori. Răspuns greșit, scăzut.
adăugat autor nawfal
Aș fi foarte îngrijorat să văd asta în codul de producție. Nu este garantat și se poate schimba în orice moment. Nu că m-am îndepărtat de soluțiile pragmatice, arată doar o lipsă de înțelegere a structurii datelor imo.
adăugat autor jamespconnor
De asemenea, puteți utiliza OrderByDescending dacă doriți să sortați într-o listă descendentă.
adăugat autor Mendokusai
A lucrat pentru mine, deși a trebuit să-l schimb ușor: Dicționar dict = dict.OrderBy (x => x.Value) .ToDictionary (x => x.Key, x => x.Value);
adăugat autor Josh

Având în vedere că aveți un dicționar, puteți să le sortați direct pe valori utilizând mai jos un singur liner:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
0
adăugat
Acest răspuns este incorect, deoarece nu poate fi ordonat dicționarul rezultat.
adăugat autor O. R. Mapper

Sortarea unei liste SortedDictionary pentru a se lega într-un control ListView folosind VB.NET:

Dim MyDictionary As SortedDictionary(Of String, MyDictionaryEntry)

MyDictionaryListView.ItemsSource = MyDictionary.Values.OrderByDescending(Function(entry) entry.MyValue)

Public Class MyDictionaryEntry ' Need Property for GridViewColumn DisplayMemberBinding
    Public Property MyString As String
    Public Property MyValue As Integer
End Class

XAML:


    
        
            
            
         
    

0
adăugat

The other answers are good, if you all you want is to have a "temporary" list sorted by Value. However, if you want to have a dictionary sorted by Key that automatically synchronizes with another dictionary that is sorted by Value, you could use the Bijection class.

Bijection allows you to initialize the collection with two existing dictionaries, so if you want one of them to be unsorted, and you want the other one to be sorted, you could create your bijection with code like

var dict = new Bijection(new Dictionary(), 
                               new SortedDictionary());

You can use dict like any normal dictionary (it implements IDictionary<>), and then call dict.Inverse to get the "inverse" dictionary which is sorted by Value.

Bijection is part of Loyc.Collections.dll, but if you want, you could simply copy the source code into your own project.

Note: In case there are multiple keys with the same value, you can't use Bijection, but you could manually synchronize between an ordinary Dictionary and a BMultiMap.

0
adăugat
Similar cu http://stackoverflow.com/questions/268321 dar poate înlocui fiecare dicționar cu SortedDictionary. Deși răspunsurile par să nu suporte valorile duplicate (presupune 1 la 1).
adăugat autor crokusek

Sau pentru distracție ai putea folosi o bunătate a extensiei LINQ:

var dictionary = new Dictionary { { "c", 3 }, { "a", 1 }, { "b", 2 } };
dictionary.OrderBy(x => x.Value)
  .ForEach(x => Console.WriteLine("{0}={1}", x.Key,x.Value));
0
adăugat

Valorile de sortare

Aceasta arată modul de sortare a valorilor într-un Dicționar. Vom vedea un program de consola pe care îl puteți compila în Visual Studio și rulați. Se adaugă cheile unui Dicționar și apoi le sortează după valorile lor. Amintiți-vă că instanțele de dicționar nu sunt sortate inițial în nici un fel. Folosim cuvântul cheie LINQ orderby într-o instrucțiune de interogare.

Clauza de comandă Program care sortează Dicționar [C #]

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // Example dictionary.
        var dictionary = new Dictionary(5);
        dictionary.Add("cat", 1);
        dictionary.Add("dog", 0);
        dictionary.Add("mouse", 5);
        dictionary.Add("eel", 3);
        dictionary.Add("programmer", 2);

        // Order by values.
        // ... Use LINQ to specify sorting by value.
        var items = from pair in dictionary
                orderby pair.Value ascending
                select pair;

        // Display results.
        foreach (KeyValuePair pair in items)
        {
            Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
        }

        // Reverse sort.
        // ... Can be looped over in the same way as above.
        items = from pair in dictionary
        orderby pair.Value descending
        select pair;
    }
}

producție

dog: 0
cat: 1
programmer: 2
eel: 3
mouse: 5
0
adăugat

Nu sortați înscrierile în dicționar. Dicționarul de clasă în .NET este implementat ca un hashtable - această structură de date nu este definită prin definiție.

Dacă trebuie să puteți relua colecția dvs. (cu cheie) - trebuie să utilizați SortedDictionary, care este implementat ca arbore de căutare binară.

În cazul tău, structura sursă este irelevantă, deoarece este sortată de un alt câmp. Încă mai trebuie să o sortați după frecvență și să o puneți într-o nouă colecție sortată după câmpul relevant (frecvență). Deci, în această colecție frecvențele sunt chei, iar cuvintele sunt valori. Deoarece multe cuvinte pot avea aceeași frecvență (și o veți folosi ca o cheie), nu puteți utiliza nici dicționarul, nici SortedDictionary (acestea necesită chei unice). Acest lucru vă va lăsa cu un SortedList.

Nu înțeleg de ce insistă să mențineți o legătură cu elementul original din dicționarul dvs. principal / primul.

Dacă obiectele din colecția dvs. aveau o structură mai complexă (mai multe câmpuri) și aveați nevoie să le puteți accesa / sorta eficient utilizând mai multe câmpuri ca chei - Probabil că veți avea nevoie de o structură personalizată de date care să compune din spațiul de stocare principal sprijină inserarea și eliminarea O (1) (LinkedList) și mai multe structuri de indexare - Dicționare / SortedDictionaries / SortedLists. Acești indici ar folosi unul din câmpurile din clasa complexă ca cheie și un pointer / referință la LinkedListNode din LinkedList ca valoare.

Va trebui să coordonați inserțiile și eliminările pentru a vă menține indexurile în sincronizare cu colecția principală (LinkedList), iar eliminările ar fi destul de costisitoare. Acest lucru este similar cu modul în care funcționează indexurile bazei de date - sunt fantastice pentru căutări, dar devin o povară atunci când trebuie să efectuați multe insecte și ștergeri.

Toate cele de mai sus sunt justificate doar dacă intenționați să faceți unele prelucrări grele. Dacă aveți nevoie doar să le trimiteți după o sortare după frecvență, atunci puteți să produceți o listă de piese (anonime):

var dict = new SortedDictionary();
// ToDo: populate dict

var output = dict.OrderBy(e => e.Value).Select(e => new {frequency = e.Value, word = e.Key}).ToList();

foreach (var entry in output)
{
    Console.WriteLine("frequency:{0}, word: {1}",entry.frequency,entry.word);
}
0
adăugat

Cea mai ușoară modalitate de a obține un Dicționar sortit este de a folosi clasa SortedDictionary construită:

//Sorts sections according to the key value stored on "sections" unsorted dictionary, which is passed as a constructor argument
System.Collections.Generic.SortedDictionary sortedSections = null;
if (sections != null)
{
    sortedSections = new SortedDictionary(sections);
}

sortedSections will contains the sorted version of sections

0
adăugat
@mbrownnyc - nope, face acest lucru presupune presupunerea sau precondiția că valorile sunt unice, ceea ce nu este garantat.
adăugat autor Roger Willcocks
După cum menționați în comentariul dvs., SortedDictionary sortează după taste. OP-ul dorește să sorteze valoarea. SortedDictionary nu ajută în acest caz.
adăugat autor Marty Neal
Ei bine ... Dacă el / ea (tu) poate, trebuie doar să setați valorile ca tastele. Am temporizat operațiunile și sorteddictionary () a fost întotdeauna câștigat de cel puțin 1 microsecund și este mult mai ușor de gestionat (deoarece cheltuielile aferente conversiei în ceva ușor de interacționat și gestionat în mod similar cu un Dicționar este 0 (este deja un sorteddictionary )).
adăugat autor mbrownnyc

Puteți sorta Dicționarul după valoare și puteți obține rezultatul în dicționar utilizând codul de mai jos:

Dictionary <> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
0
adăugat
Și de ce adăugați acest răspuns atunci când acesta este deja răspuns?
adăugat autor nawfal
Prin plasarea elementelor sortate înapoi în dicționar, acestea nu mai sunt garantate pentru a fi sortate atunci când enumerați noul dicționar.
adăugat autor Marty Neal

Să presupunem că avem un dicționar ca

   Dictionary dict = new Dictionary();
   dict.Add(21,1041);
   dict.Add(213, 1021);
   dict.Add(45, 1081);
   dict.Add(54, 1091);
   dict.Add(3425, 1061);
   sict.Add(768, 1011);

1) puteți utiliza dicționarul temporar pentru a stoca valori ca :

        Dictionary dctTemp = new Dictionary();

        foreach (KeyValuePair pair in dict.OrderBy(key => key.Value))
        {
            dctTemp .Add(pair.Key, pair.Value);
        }
0
adăugat
Dictionary dic= new Dictionary();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
0
adăugat
De asemenea, incorect. Consultați aici: stackoverflow.com/a/4007787/463828
adăugat autor Philipp M