Jak można sortować według wartości słownik?

głosy
671

Często mam do sortowania słownika, składające się z kluczy i wartości przez wartość. Na przykład, mam skrót słów i odpowiednich częstotliwościach, które chcę zamówić przez częstotliwość.

Jest to SortedListco jest dobre dla pojedynczej wartości (powiedzmy częstotliwość), że chcę mapować go do słowa.

SortedDictionary zlecenia przez klucz, a nie wartości. Niektórzy uciekają się do niestandardowej klasy , ale jest tam czystsze sposób?

Utwórz 02/08/2008 o 01:40
źródło użytkownik
W innych językach...                            


17 odpowiedzi

głosy
473

Używać 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;

To także pozwala na dużą elastyczność w które można wybrać top 10, 20 10%, itd. Albo jeśli używasz indeksu częstotliwości słowo za type-ahead, można również zawierać StartsWithklauzulę, jak również.

Odpowiedział 04/08/2008 o 16:22
źródło użytkownik

głosy
459

Posługiwać się:

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);
    }
);

Skoro jesteś kierowanie .NET 2.0 lub wyżej, to można uprościć do składni lambda - to odpowiednik, ale krótszy. Jeśli kierujesz .NET 2.0 można użyć tej składni tylko jeśli używasz kompilatora Visual Studio 2008 (lub powyżej).

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));
Odpowiedział 02/08/2008 o 02:15
źródło użytkownik

głosy
179
var ordered = dict.OrderBy(x => x.Value);
Odpowiedział 11/11/2010 o 18:16
źródło użytkownik

głosy
148

Rozglądając się wokół, a korzystanie z 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 widziałem i jest podobny do sposobu postępowania z mieszań Ruby.

Odpowiedział 02/08/2008 o 01:43
źródło użytkownik

głosy
140

Można sortować słownika przez wartość i zapisać go z powrotem do siebie (tak, że kiedy foreach nad nim wartości wyjdzie w kolejności):

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

Pewnie, że nie może być poprawne, ale to działa.

Odpowiedział 22/06/2011 o 11:26
źródło użytkownik

głosy
56

Na wysokim poziomie, nie masz innego wyboru, następnie przejść przez cały słownik i spojrzeć na każdej wartości.

Może to pomoże: http://bytes.com/forum/thread563638.html Kopiowanie / wklejanie John Timney:

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);
    }
);
Odpowiedział 02/08/2008 o 01:47
źródło użytkownik

głosy
22

Że nigdy nie móc sortować słownika tak. Nie są one właściwie uporządkowane. Gwarancje słownika jest to, że klucz i wartość kolekcje są iterable i wartości mogą być pobierane przez indeks lub klucz, ale tutaj ma gwarancji określonej kolejności. Stąd trzeba by dostać parę nazwa wartość w postaci listy.

Odpowiedział 19/12/2008 o 23:47
źródło użytkownik

głosy
16

Nie sortowania wpisów w słowniku. Słownik klasy w .NET jest zaimplementowany jako hashtable - to struktura danych nie jest sortable definicji.

Jeśli potrzebujesz, aby móc iteracyjne nad kolekcji (przez klucz) - trzeba użyć SortedDictionary, który jest zaimplementowany jako binarne drzewo poszukiwań.

W twoim przypadku, jednak struktura źródłem jest bez znaczenia, ponieważ jest posortowana według innej dziedzinie. Nadal będzie trzeba posortować je według częstotliwości i umieścić go w nowej kolekcji posortowane według danej dziedzinie (częstotliwości). Więc w tej kolekcji częstotliwości są klucze i słowa są wartościami. Ponieważ wiele słów może mieć taką samą częstotliwość (i masz zamiar używać go jako klucz) nie można używać ani Słownika ani SortedDictionary (wymagają one unikalne klucze). Pozostaje Ci SortedList.

Nie rozumiem, dlaczego nalegają na utrzymanie link do oryginalnego elementu w głównym / pierwszego słownika.

Jeżeli przedmioty w swojej kolekcji miał bardziej złożoną strukturę (więcej pól) i potrzebne, aby móc skutecznie dostępu / sortować je przy użyciu kilku różnych pól jako kluczy - Pewnie musiałby niestandardową strukturę danych, które składają się z pamięci głównej, które obsługuje O (1) do wprowadzania i usuwania (LinkedList) i kilka struktur indeksujące - Słowniki / SortedDictionaries / SortedLists. Indeksy te będą korzystać z jednego z pól z klasy złożonej jako klucz i wskaźnik / odniesienia do LinkedListNode w LinkedList jako wartość.

trzeba by koordynować wstawki i usuwania, aby utrzymać indeksy w synchronizacji z kolekcji (główny) i usunięć LinkedList byłoby dość drogie myślałem. Jest to podobne do tego, jak działają indeksy bazy danych - są fantastyczne dla wyszukiwań, ale stają się ciężarem, gdy trzeba wykonać wiele insetions i skreśleń.

Wszystkie powyższe jest tylko uzasadnione, jeśli masz zamiar zrobić kilka ciężkich przetwarzanie look-up. Jeśli potrzebne jest tylko do wyjścia im raz sortowane według częstotliwości następnie można po prostu stworzyć listę krotek (anonim):

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);
}
Odpowiedział 13/12/2012 o 07:19
źródło użytkownik

głosy
12
Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
Odpowiedział 20/07/2015 o 11:01
źródło użytkownik

głosy
10

Uporządkuj wartości

To pokazuje, jak sortować wartości w słowniku. Widzimy program konsoli można skompilować w Visual Studio i metę. Dodaje klucze do słownika, a następnie sortuje je według ich wartości. Pamiętaj, że słownik przypadki nie są wstępnie posortowane w jakikolwiek sposób. Używamy orderby słowa kluczowego LINQ w komunikacie zapytania.

Program klauzula OrderBy że sortuje słownik [C #]

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

class Program
{
    static void Main()
    {
        // Example dictionary.
        var dictionary = new Dictionary<string, int>(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<string, int> 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;
    }
}

Wydajność

dog: 0
cat: 1
programmer: 2
eel: 3
mouse: 5
Odpowiedział 20/07/2012 o 10:49
źródło użytkownik

głosy
10

Lub dla zabawy można korzystać z niektórych LINQ rozszerzenie dobroci:

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));
Odpowiedział 30/06/2010 o 12:12
źródło użytkownik

głosy
9

Sortowanie SortedDictionarylisty do wiązania do ListViewkontroli przy użyciu 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>
Odpowiedział 23/04/2010 o 10:36
źródło użytkownik

głosy
5

Pozostałe odpowiedzi są dobre, jeśli chcesz to mieć „tymczasowy” Lista posortowane przez wartość. Jednakże, jeśli chcesz mieć słownika Weaver Key, która automatycznie synchronizuje się z innego słownika, który jest posortowana według Value, można użyć Bijection<K1, K2>klasy .

Bijection<K1, K2> pozwala zainicjować kolekcję z dwóch istniejących słowników, więc jeśli chcesz, aby jeden z nich będzie bez sortowania, a chcesz drugi mają być posortowane, można stworzyć swój bijection z kodem jak

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

Można używać dictjak każdy normalny słowniku (realizuje IDictionary<>), a następnie zadzwonić dict.Inverse, aby uzyskać „odwrotny” słownika, który jest posortowana według Value.

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

Uwaga : W przypadku, gdy istnieje wiele klucze o tej samej wartości, nie można używać Bijection, ale można ręcznie synchronizować pomiędzy zwykłym Dictionary<Key,Value>a BMultiMap<Value,Key>.

Odpowiedział 26/02/2016 o 07:15
źródło użytkownik

głosy
5

Najprostszym sposobem, aby uzyskać posortowane Dictionary jest użycie wbudowanego w SortedDictionaryklasie:

//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 wola zawiera posortowaną wersję sections

Odpowiedział 02/04/2010 o 23:36
źródło użytkownik

głosy
4

Załóżmy, że mamy słownika 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żna 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);
        }
Odpowiedział 02/02/2015 o 10:46
źródło użytkownik

głosy
-2

Biorąc pod uwagę, że masz słownika można sortować je bezpośrednio na wartościach poniżej jednej z wykorzystaniem liniowej:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Odpowiedział 31/05/2014 o 23:30
źródło użytkownik

głosy
-2

Można sortować słownika wartości i uzyskać wynik w słowniku za pomocą poniższego kodu:

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
Odpowiedział 24/07/2012 o 13:24
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more