Hoe maak je een woordenboek van de waarde sorteren?

stemmen
671

Ik heb vaak een woordenboek te sorteren, bestaande uit sleutels en waarden, in waarde. Zo heb ik een hash van woorden en respectieve frequenties, dat wil bestellen frequentie.

Er is een SortedListdie goed is voor een enkele waarde (zeg frequentie), die ik wil het terug naar het woord kaart te brengen.

SortedDictionary orders met een sleutel, geen toegevoegde waarde. Sommige toevlucht tot een aangepaste klasse , maar is er een schonere manier?

De vraag is gesteld op 02/08/2008 om 01:40
bron van user
In andere talen...                            


18 antwoorden

stemmen
148

Rond te kijken, en met behulp van enkele C # 3.0-kenmerken kunnen we dit doen:

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

Dit is de schoonste manier die ik heb gezien en is vergelijkbaar met de Ruby manier van omgaan met hashes.

antwoordde op 02/08/2008 om 01:43
bron van user

stemmen
56

Op een hoog niveau, heb je geen andere keus dan te lopen door het hele woordenboek en kijk naar elke waarde.

Misschien dat dit helpt: http://bytes.com/forum/thread563638.html kopiëren / plakken van 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);
    }
);
antwoordde op 02/08/2008 om 01:47
bron van user

stemmen
459

Gebruik:

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

Omdat je richt je .NET 2.0 of hoger, kunt u deze vereenvoudigen in lambda syntax - het is gelijkwaardig, maar korter. Als je gericht bent .NET 2.0 kunt u alleen syntax gebruiken als u de compiler van Visual Studio 2008 (of hoger).

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));
antwoordde op 02/08/2008 om 02:15
bron van user

stemmen
473

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

Dit zou ook zorgen voor een grote flexibiliteit in dat u de top 10 kan selecteren, 20 10%, enz. Of als u uw woord frequentie-index voor type-ahead, je kon ook StartsWithclausule ook.

antwoordde op 04/08/2008 om 16:22
bron van user

stemmen
22

Je zou nooit in staat zijn om een ​​woordenboek toch sorteren. Ze zijn niet echt besteld. De garanties voor een woordenboek is dat de sleutel en waarde collecties zijn iterable en waarden kunnen worden opgehaald door de index of sleutel, maar hier is geen garantie voor een bepaalde volgorde. Vandaar dat je nodig zou hebben om de naam waarde paar krijgen in een lijst.

antwoordde op 19/12/2008 om 23:47
bron van user

stemmen
5

De eenvoudigste manier om een gesorteerde Dictionary te krijgen is het gebruik van de ingebouwde 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 testament bevat de gesorteerde versie van sections

antwoordde op 02/04/2010 om 23:36
bron van user

stemmen
9

Sorteren van een SortedDictionarylijst te binden in een ListViewcontrole met behulp van 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>
antwoordde op 23/04/2010 om 10:36
bron van user

stemmen
10

Of voor de lol je kan wat LINQ extensie goedheid:

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));
antwoordde op 30/06/2010 om 12:12
bron van user

stemmen
179
var ordered = dict.OrderBy(x => x.Value);
antwoordde op 11/11/2010 om 18:16
bron van user

stemmen
140

U kunt een woordenboek sorteren op waarde en sla het terug naar zichzelf (zodat wanneer u foreach overheen de waarden uit te komen in volgorde):

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

Tuurlijk, kan het niet juist zijn, maar het werkt.

antwoordde op 22/06/2011 om 11:26
bron van user

stemmen
10

Sorteer waarden

Deze laten zien hoe de waarden in een Dictionary sorteren. We zien een console programma kan je het compileren in Visual Studio en uit te voeren. Het voegt sleutels van een woordenboek en vervolgens sorteert ze door hun waarden. Vergeet niet dat woordenboek instanties worden in eerste instantie niet gesorteerd in any way. We maken gebruik van de LINQ orderby zoekwoord in een query verklaring.

OrderBy clausule programma dat sorteert woordenboek [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;
    }
}

uitgang

dog: 0
cat: 1
programmer: 2
eel: 3
mouse: 5
antwoordde op 20/07/2012 om 10:49
bron van user

stemmen
-2

U kunt de Dictionary sorteren op waarde en krijg het resultaat in woordenboek met behulp van de onderstaande code:

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
antwoordde op 24/07/2012 om 13:24
bron van user

stemmen
16

Je hebt geen items in de Dictionary sorteren. Klasse Dictionary in .NET is geïmplementeerd als een hash - deze datastructuur is niet sorteerbaar per definitie.

Als u nodig hebt om te kunnen herhalen over uw collectie (met een sleutel) - je moet SortedDictionary, die wordt uitgevoerd als een binaire zoekboom gebruiken.

In uw geval, maar de bron structuur is niet relevant, omdat het wordt gesorteerd op een ander veld. Je zou nog steeds nodig om het te sorteren op frequentie en zet het in een nieuwe collectie naargelang het betreffende veld (frequentie). Dus in deze collectie de frequenties zijn sleutels en woorden zijn waarden. Aangezien veel woorden dezelfde frequentie kan hebben (en je gaat om het te gebruiken als een sleutel) kunt u noch woordenboek noch SortedDictionary (die zij nodig hebben unieke sleutels) niet gebruiken. Dit laat je met een SortedList.

Ik begrijp niet waarom je aandringen op het handhaven van een link naar het oorspronkelijke artikel in uw main / eerste woordenboek.

Als de objecten in uw collectie had een meer complexe structuur (meer velden) en u die nodig is om efficiënt te kunnen toegang / sorteer ze met behulp van verschillende gebieden als sleutels - Je zou waarschijnlijk een aangepaste datastructuur die zou bestaan ​​uit de belangrijkste opslagruimte nodig dat ondersteunt O (1) inbrengen en verwijderen (LinkedList) en diverse indexeren structuren - woordenboeken / SortedDictionaries / SortedLists. Deze indexen zou een van de velden uit uw complex klasse als een sleutel en een pointer / verwijzing naar de LinkedListNode in de LinkedList als een waarde.

Je zou moeten inbrengen en verhuizingen te coördineren om uw indexen synchroon te houden met de belangrijkste collectie (LinkedList) en verwijderingen vrij duur Ik zou denken zou zijn. Dit is vergelijkbaar met hoe de database indexen werken - ze zijn fantastisch voor lookups, maar ze uitgegroeid tot een last wanneer u veel insetions en verwijderingen uit te voeren.

Al het bovenstaande is alleen gerechtvaardigd als je gaat om een ​​aantal look-up zware verwerking te doen. Als je alleen nodig hebt om deze uit te voeren zodra naargelang hun frequentie dan kun je gewoon produceren een lijst van (anonieme) tupels:

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);
}
antwoordde op 13/12/2012 om 07:19
bron van user

stemmen
-2

Gezien je een woordenlijst kan je ze rechtstreeks gekozen op waarden met behulp van de onderstaande one-liner:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
antwoordde op 31/05/2014 om 23:30
bron van user

stemmen
4

Stel we hebben een woordenboek als

   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) die u kunt gebruiken 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);
        }
antwoordde op 02/02/2015 om 10:46
bron van user

stemmen
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);
antwoordde op 20/07/2015 om 11:01
bron van user

stemmen
5

De andere antwoorden zijn goed, als je alles wat je wilt is om een "tijdelijke" lijst naargelang hun waarde hebben. Echter, als je wilt een woordenboek naargelang hebben Keydat synchroniseert automatisch met een ander woordenboek dat wordt gesorteerd Value, kunt u het gebruiken Bijection<K1, K2>klasse .

Bijection<K1, K2> kunt u de collectie te initialiseren met twee bestaande woordenboeken, dus als je één van hen willen ongesorteerd zijn, en u wilt de ander te sorteren, kunt u uw bijectie maken met code zoals

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

U kunt gebruiken dictals een normale woordenboek (zij voert IDictionary<>), en dan bellen dict.Inversenaar de "omgekeerde" woordenlijst die wordt gesorteerd op krijgen Value.

Bijection<K1, K2>maakt deel uit van Loyc.Collections.dll , maar als je wilt, kan je gewoon het kopiëren source code in uw eigen project.

Opmerking : In het geval dat er meerdere toetsen met dezelfde waarde, kun je niet gebruiken Bijection, maar je kunt handmatig synchroniseren tussen een gewone Dictionary<Key,Value>en een BMultiMap<Value,Key>.

antwoordde op 26/02/2016 om 07:15
bron van user

stemmen
0

Eigenlijk in C #, Woordenboeken dint hebben sort () methoden, zoals u meer geïnteresseerd in een soort van waarden zijn, je kan krijgen waarden totdat u hen sleutel, kortom, je moet doorlopen hen, met behulp van LINQ's Uitzoeken door,

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
}

kunt u een truc te doen,

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

of

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

zijn ook afhankelijk van wat voor soort waarden die u opslaat,
is deze single (zoals koord, int) of meerdere (zoals List, Array, door de gebruiker gedefinieerde klasse),
als enige je lijst van kunnen maken dan van toepassing soort.
als de gebruiker gedefinieerde klasse, dan moet die klasse IComparable uit te voeren,
ClassName: IComparable<ClassName>en negeren compareTo(ClassName c) omdat ze meer sneller dan LINQ, en nog veel meer object-georiënteerd.

antwoordde op 26/02/2019 om 12:39
bron van user

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