Hvordan sorterer du en ordbok av verdi?

stemmer
688

Jeg har ofte å sortere en ordbok, som består av nøkler og verdier, etter verdi. For eksempel har jeg en hash av ord og respektive frekvenser, som jeg ønsker å bestille ved frekvens.

Det er en SortedListsom er bra for en enkelt verdi (si frekvens), som jeg ønsker å kartlegge den tilbake til ordet.

SortedDictionary bestillinger av nøkkelen, ikke verdi. Noen tyr til en egendefinert klasse , men er det en renere måte?

Publisert på 02/08/2008 klokken 00:40
kilden bruker
På andre språk...                            


17 svar

stemmer
481

Bruk 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;

Dette vil også gi rom for stor fleksibilitet ved at du kan velge topp 10, 20 10%, etc. Eller hvis du bruker ordet frekvens indeks for type-ahead, kan du også inkludere StartsWithklausulen også.

Svarte 04/08/2008 kl. 15:22
kilden bruker

stemmer
470

Bruk:

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

Siden du målretter .NET 2.0 eller høyere, kan du forenkle dette inn i lambda syntaks - det er tilsvarende, men kortere. Hvis du målretter .NET 2.0 kan du bare bruke denne syntaksen hvis du bruker kompilatoren fra Visual Studio 2008 (eller nyere).

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));
Svarte 02/08/2008 kl. 01:15
kilden bruker

stemmer
189
var ordered = dict.OrderBy(x => x.Value);
Svarte 11/11/2010 kl. 17:16
kilden bruker

stemmer
150

Leter rundt, og ved hjelp av noen C # 3.0 funksjoner vi kan gjøre dette:

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

Dette er den reneste måten jeg har sett, og ligner på Ruby måte å håndtere hashes.

Svarte 02/08/2008 kl. 00:43
kilden bruker

stemmer
142

Du kan sortere en ordbok av verdi og lagre den tilbake til seg selv (slik at når du foreach over det de verdiene kommer ut i rekkefølge):

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

Jada, det kan ikke være riktig, men det fungerer.

Svarte 22/06/2011 kl. 10:26
kilden bruker

stemmer
57

På et høyt nivå, har du ingen andre valg deretter å gå gjennom hele ordbok og se på hver verdi.

Kanskje dette hjelper: http://bytes.com/forum/thread563638.html Kopier / lime fra 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);
    }
);
Svarte 02/08/2008 kl. 00:47
kilden bruker

stemmer
22

Du vil aldri være i stand til å sortere en ordbok uansett. De er faktisk ikke bestilt. Garantiene for en ordbok er at nøkkel og verdi samlinger er iterable, og verdier kan hentes ved indeks eller nøkkel, men her er ingen garanti for noen bestemt rekkefølge. Derfor ville du trenger for å få navnet verdien paret inn i en liste.

Svarte 19/12/2008 kl. 22:47
kilden bruker

stemmer
16

Du trenger ikke sortere oppføringer i ordbok. Dictionary klasse i NET er implementert som en hashtabellen - denne datastruktur er ikke kan sorteres ved definisjon.

Hvis du trenger å være i stand til å iterere over samlingen din (med nøkkel) - du må bruke SortedDictionary, som er implementert som et binært søketre.

I ditt tilfelle, men kilden strukturen er irrelevant, fordi den er sortert etter et annet felt. Du vil fortsatt trenger å sortere det etter frekvens og legg den i en ny samling sortert etter det aktuelle feltet (frekvens). Så i denne samlingen frekvensene er nøkler og ord er verdier. Siden mange ord kan ha samme frekvens (og du kommer til å bruke den som en nøkkel) du ikke kan bruke verken ordbok eller SortedDictionary (de krever unike nøkler). Dette etterlater deg med en SortedList.

Jeg forstår ikke hvorfor du insisterer på å opprettholde en kobling til det opprinnelige elementet i hoved / første ordbok.

Hvis objektene i samlingen hadde en mer kompleks struktur (flere felt), og du måtte være i stand til å effektivt tilgang / sortere dem ved hjelp av flere forskjellige felt som nøkler - Du ville trolig trenger en tilpasset datastruktur som vil bestå av hovedlageret som støtter O (1) innsetting og fjerning (Linked) og flere indekseringsstrukturer - ordbøker / SortedDictionaries / SortedLists. Disse indeksene ville bruke ett av feltene fra komplekse klasse som en nøkkel og en peker / referanse til LinkedListNode i Linked som en verdi.

Du må koordinere innsettinger for å holde indeksene synkronisert med hoved samling (Linked) og fjerning ville være ganske dyrt jeg tror. Dette ligner på hvordan database indekser fungerer - de er fantastisk for oppslag, men de blir en byrde når du trenger å utføre mange insetions og slettinger.

Alle de ovennevnte er bare berettiget hvis du kommer til å gjøre noen look-up tung prosessering. Hvis du bare trenger å skrive dem en gang sortert etter frekvens så kan du bare lage en liste over (anonyme) tupler:

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);
}
Svarte 13/12/2012 kl. 06:19
kilden bruker

stemmer
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);
Svarte 20/07/2015 kl. 11:01
kilden bruker

stemmer
10

Sorter verdier

Dette viser hvordan å sortere verdiene i en ordbok. Vi ser en konsoll program du kan kompilere i Visual Studio og kjøre. Det legger nøklene til en ordbok og deretter sorterer dem etter deres verdier. Husk at Ordbok tilfeller ikke er i utgangspunktet sortert på noen måte. Vi bruker LINQ orderby søkeordet i en spørring uttalelse.

Orderby klausul Program som sorterer ordbok [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;
    }
}

Produksjon

dog: 0
cat: 1
programmer: 2
eel: 3
mouse: 5
Svarte 20/07/2012 kl. 09:49
kilden bruker

stemmer
10

Eller for moro skyld kan du bruke noen LINQ forlengelse godhet:

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));
Svarte 30/06/2010 kl. 11:12
kilden bruker

stemmer
9

Sortering en SortedDictionaryliste til å binde til en ListViewkontroll ved hjelp av 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>
Svarte 23/04/2010 kl. 09:36
kilden bruker

stemmer
5

De andre svarene er bra, hvis du alt du ønsker er å ha en "midlertidig" liste sortert etter verdi. Men hvis du vil ha en ordbok sortert etter Keysom automatisk synkroniserer med en annen ordbok som er sortert etter Value, kan du bruke den Bijection<K1, K2>klassen .

Bijection<K1, K2> gjør det mulig å initialisere samlingen med to eksisterende ordbøker, så hvis du ønsker en av dem til å være usortert, og du vil at andre skal sorteres, kan du opprette din Bijeksjon med kode som

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

Du kan bruke dictsom en vanlig ordbok (den implementerer IDictionary<>), og deretter ringe dict.Inversefor å få den "omvendte" ordbok som er sortert etter Value.

Bijection<K1, K2>er en del av Loyc.Collections.dll , men hvis du vil, kan du bare kopiere kildekoden til ditt eget prosjekt.

Merk : I tilfelle det er flere nøkler med samme verdi, kan du ikke bruke Bijection, men du kan synkronisere manuelt mellom en vanlig Dictionary<Key,Value>og en BMultiMap<Value,Key>.

Svarte 26/02/2016 kl. 07:15
kilden bruker

stemmer
5

Den enkleste måten å få en sortert Dictionary er å bruke den innebygde SortedDictionaryklasse:

//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 vilje inneholder den sorterte versjonen av sections

Svarte 02/04/2010 kl. 22:36
kilden bruker

stemmer
4

Anta at vi har en ordbok som

   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) du kan bruke 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);
        }
Svarte 02/02/2015 kl. 10:46
kilden bruker

stemmer
-2

Gitt at du har en ordbok kan du sortere dem direkte på verdier som bruker under en liner:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Svarte 31/05/2014 kl. 22:30
kilden bruker

stemmer
-2

Du kan sortere ordbok av verdi og få resultatet i ordboken bruke koden under:

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
Svarte 24/07/2012 kl. 12:24
kilden bruker

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