Jak posortować słownik według wartości?

Często muszę sortować słownik, składający się z kluczy i wartości, według wartości. Na przykład, mam hash słów i odpowiednich częstotliwości, które chcę zamówić według częstotliwości.

Istnieje SortedList, który jest dobry dla pojedynczej wartości (powiedzmy częstotliwości), że chcę odwzorować go z powrotem do słowa.

SortedDictionary zamówienia według klucza, a nie wartości. Niektórzy uciekają się do klasy niestandardowej , ale czy jest czystszy sposób?

19 answers

Użycie:

using System.Linq.Enumerable;
...
List<KeyValuePair<string, string>> myList = aDictionary.ToList();

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

Ponieważ kierujesz. NET w wersji 2.0 lub nowszej, możesz uprościć to do składni lambda - jest to równoważne, ale krótsze. Jeśli kierujesz. NET 2.0, możesz użyć tej składni tylko wtedy, gdy używasz kompilatora z Visual Studio 2008 (lub nowszego).

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));
 532
Author: Leon Bambrick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-31 23:01:42

Użyj LINQ:

Dictionary<string, int> myDict = new Dictionary<string, int>();
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;

Pozwoliłoby to również na dużą elastyczność, ponieważ można wybrać top 10, 20 10%, itp. Lub jeśli używasz indeksu częstotliwości słów dla type-ahead, Możesz również dołączyć klauzulę StartsWith.

 537
Author: caryden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-31 23:02:53
var ordered = dict.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
 285
Author: sean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-31 08:42:10

Rozglądając się dookoła i używając niektórych funkcji C# 3.0 możemy to zrobić:

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

Jest to najczystszy sposób, jaki widziałem i jest podobny do Ruby sposób obchodzenia się z hashami.

 169
Author: Kalid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-29 17:11:28

Możesz posortować Słownik według wartości i zapisać go z powrotem do siebie (tak, aby po przekroczeniu go wartości wyszły w kolejności):

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

Jasne, może to nie jest poprawne, ale działa.

 165
Author: Matt Frear,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-30 09:29:19

Na wysokim poziomie, nie masz innego wyboru niż przejść przez cały słownik i spojrzeć na każdą wartość.

Może to pomoże: http://bytes.com/forum/thread563638.html Kopiowanie / wklejanie od Johna Timneya:

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

List<KeyValuePair<string, string>> myList = new List<KeyValuePair<string, string>>(s);
myList.Sort(
    delegate(KeyValuePair<string, string> firstPair,
    KeyValuePair<string, string> nextPair)
    {
        return firstPair.Value.CompareTo(nextPair.Value);
    }
);
 60
Author: Michael Stum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-17 07:24:37

I tak nie będziesz w stanie posortować słownika. Nie są one faktycznie zamówione. Gwarancją dla słownika jest to, że zbiory klucza i wartości są iteracyjne, a wartości mogą być pobierane przez indeks lub klucz, ale nie ma gwarancji określonej kolejności. W związku z tym trzeba będzie uzyskać para wartość nazwa do listy.

 26
Author: Roger Willcocks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-15 02:00:23

Nie sortujesz wpisów w słowniku. Klasa słownika w. NET jest zaimplementowana jako hashtable - ta struktura danych nie jest z definicji sortowalna.

Jeśli chcesz mieć możliwość iteracji po swojej kolekcji (według klucza) - musisz użyć SortedDictionary, który jest zaimplementowany jako binarne drzewo wyszukiwania.

W Twoim przypadku struktura źródła nie ma znaczenia, ponieważ jest posortowana według innego pola. Nadal będziesz musiał posortować go według częstotliwości i umieścić w nowym kolekcja posortowana według odpowiedniego pola (częstotliwość). Więc w tym zbiorze częstotliwości są kluczami, a słowa są wartościami. Ponieważ wiele słów może mieć tę samą częstotliwość (i użyjesz jej jako klucza), nie możesz używać ani słownika, ani SortedDictionary (wymagają unikalnych kluczy). To pozostawia Ci sortowaną listę.

Nie rozumiem, dlaczego nalegasz na utrzymywanie linku do oryginalnej pozycji w głównym/pierwszym słowniku.

Jeśli obiekty w Twojej kolekcji miały bardziej złożona struktura (więcej pól) i trzeba było być w stanie efektywnie uzyskać dostęp/sortować je za pomocą kilku różnych pól jako kluczy - prawdopodobnie potrzebna byłaby niestandardowa struktura danych, która składałaby się z głównego magazynu, który obsługuje o(1) wstawianie i usuwanie (LinkedList) i kilka struktur indeksujących - Słowniki/SortedDictionaries/SortedLists. Indeksy te będą używać jednego z pól z Twojej złożonej klasy jako klucza i wskaźnika / odniesienia do LinkedListNode w LinkedList jako wartość.

Trzeba koordynować wstawiania i usuwania, aby utrzymać swoje indeksy w synchronizacji z główną kolekcją (LinkedList) i usuwania byłoby dość drogie, jak sądzę. Jest to podobne do tego, jak działają indeksy baz danych - są fantastyczne dla wyszukiwania, ale stają się ciężarem, gdy trzeba wykonać wiele wstawiania i usuwania.

Wszystkie powyższe jest uzasadnione tylko wtedy, gdy masz zamiar zrobić jakieś spojrzenie-up ciężkich przetwarzania. Jeśli musisz je wypisać tylko raz posortowane według częstotliwość, wtedy można po prostu stworzyć listę (anonimowych) krotek:

var dict = new SortedDictionary<string, int>();
// 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);
}
 21
Author: Zar Shardan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-31 07:43:51
Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
 15
Author: mrfazolka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-20 11:01:19

Albo dla Zabawy przydałoby się jakieś rozszerzenie LINQ:

var dictionary = new Dictionary<string, int> { { "c", 3 }, { "a", 1 }, { "b", 2 } };
dictionary.OrderBy(x => x.Value)
  .ForEach(x => Console.WriteLine("{0}={1}", x.Key,x.Value));
 12
Author: mythz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-30 11:12:21

Sortowanie listy SortedDictionary do połączenia w kontrolkę ListView za pomocą 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:

<ListView Name="MyDictionaryListView">
    <ListView.View>
        <GridView>
            <GridViewColumn DisplayMemberBinding="{Binding Path=MyString}" Header="MyStringColumnName"></GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding Path=MyValue}" Header="MyValueColumnName"></GridViewColumn>
         </GridView>
    </ListView.View>
</ListView>
 10
Author: BSalita,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-31 23:04:12

Inne odpowiedzi są dobre, jeśli wszystko, co chcesz, to mieć "tymczasową" listę posortowaną według wartości. Jeśli jednak chcesz mieć słownik posortowany według Key, który automatycznie synchronizuje z innym słownikiem posortowanym według Value, możesz użyć Bijection<K1, K2> Klasa .

Bijection<K1, K2> pozwala na zainicjowanie kolekcji za pomocą dwóch istniejących słowników, więc jeśli chcesz, aby jeden z nich był niesortowany, a drugi sortowany, możesz utworzyć swój bijection with code like

var dict = new Bijection<Key, Value>(new Dictionary<Key,Value>(), 
                               new SortedDictionary<Value,Key>());

Możesz użyć dict Jak każdy zwykły słownik (implementuje IDictionary<K, V>), a następnie wywołać dict.Inverse, aby uzyskać "odwrotny" słownik, który jest sortowany według Value.

Bijection<K1, K2> jest częścią Loyc.Kolekcje.dll, Ale jeśli chcesz, możesz po prostu skopiować kod źródłowy do własnego projektu.

Uwaga: W przypadku, gdy istnieje wiele kluczy o tej samej wartości, nie można użyć Bijection, ale można ręcznie zsynchronizować między zwykłe Dictionary<Key,Value> i a BMultiMap<Value,Key>.

 7
Author: Qwertie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-16 15:51:28

Najprostszym sposobem uzyskania posortowanego słownika jest użycie wbudowanej klasy SortedDictionary:

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

sortedSections będzie zawierać posortowaną wersję sections

 7
Author: Alex Ruiz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-26 19:05:40

W C# słowniki nie mają metod sort (). Ponieważ jesteś bardziej zainteresowany sortowaniem według wartości, nie możesz uzyskać wartości, dopóki nie podasz im klucza. W skrócie, musisz je iterować używając LINQ ' s OrderBy(),

var items = new Dictionary<string, int>();
items.Add("cat", 0);
items.Add("dog", 20);
items.Add("bear", 100);
items.Add("lion", 50);

// Call OrderBy() method here on each item and provide them the IDs.
foreach (var item in items.OrderBy(k => k.Key))
{
    Console.WriteLine(item);// items are in sorted order
}

Możesz zrobić jedną sztuczkę:

var sortedDictByOrder = items.OrderBy(v => v.Value);

Lub:

var sortedKeys = from pair in dictName
            orderby pair.Value ascending
            select pair;

Zależy również od tego, jakie wartości przechowujesz: single (jak string, int) lub multiple (jak List, Array, user defined class). Jeśli jest pojedynczy, możesz utworzyć jego listę, a następnie zastosować sortowanie.
Jeśli jest to klasa zdefiniowana przez użytkownika, wtedy ta klasa musi zaimplementować IComparable, ClassName: IComparable<ClassName> i nadpisać compareTo(ClassName c), ponieważ są one szybsze i bardziej zorientowane obiektowo niż LINQ.

 4
Author: Ashish Kamble,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-27 00:07:48

Załóżmy, że mamy słownik jako

   Dictionary<int, int> dict = new Dictionary<int, int>();
   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) możesz użyć temporary dictionary to store values as :

        Dictionary<int, int> dctTemp = new Dictionary<int, int>();

        foreach (KeyValuePair<int, int> pair in dict.OrderBy(key => key.Value))
        {
            dctTemp .Add(pair.Key, pair.Value);
        }
 3
Author: Akshay Kapoor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-02 11:21:58

Wymagana przestrzeń nazw: using System.Linq;

Dictionary<string, int> counts = new Dictionary<string, int>();
counts.Add("one", 1);
counts.Add("four", 4);
counts.Add("two", 2);
counts.Add("three", 3);

Order by desc:

foreach (KeyValuePair<string, int> kvp in counts.OrderByDescending(key => key.Value))
{
// some processing logic for each item if you want.
}

Order by Asc:

foreach (KeyValuePair<string, int> kvp in counts.OrderBy(key => key.Value))
{
// some processing logic for each item if you want.
}
 0
Author: Jaydeep Shil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-18 17:35:06

Sortowanie i drukowanie:

var items = from pair in players_Dic
                orderby pair.Value descending
                select pair;

// Display results.
foreach (KeyValuePair<string, int> pair in items)
{
    Debug.Log(pair.Key + " - " + pair.Value);
}

Zmień malejąco na acending aby zmienić kolejność sortowania

 0
Author: PeterK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-15 06:30:08

Możesz posortować Słownik według wartości i uzyskać wynik w słowniku używając poniższego kodu:

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
 -2
Author: pawan Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-24 12:30:47

Jeśli masz słownik, możesz posortować je bezpośrednio po wartościach używając poniższej linijki:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
 -2
Author: aggaton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-31 22:30:00