Как вы сортируете словарь по значению?

Мне часто приходится сортировать словарь, состоящий из ключей и значений, по значению. Например, у меня есть хеш слов и соответствующих частот, которые я хочу заказать по частоте.

Существует SortedList, который хорош для одного значения (например, частоты), что я хочу отнести его к слову.

SortedDictionary заказывает ключ, а не значение. Некоторые прибегают к пользовательскому классу, но есть ли более чистый способ?

Ответ 1

Использование:

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

Поскольку вы нацеливаете .NET 2.0 или выше, вы можете упростить это в синтаксисе лямбда - это эквивалентно, но короче. Если вы настроили таргетинг на .NET 2.0, вы можете использовать этот синтаксис только в том случае, если вы используете компилятор из Visual Studio 2008 (или выше).

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));

Ответ 2

Используйте 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;

Это также обеспечит большую гибкость в том, что вы можете выбрать лучшие 10, 20 10% и т.д. Или, если вы используете свой индекс частоты слов для type-ahead, вы также можете включить предложение StartsWith.

Ответ 3

var ordered = dict.OrderBy(x => x.Value);

Ответ 4

Оглядываясь и используя некоторые функции С# 3.0, мы можем это сделать:

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

Это самый чистый способ, который я видел и похож на рубиновый способ обработки хэшей.

Ответ 5

Вы можете сортировать словарь по значению и сохранять его обратно в себя (так что, когда вы его просматриваете, значения выходят в порядок):

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

Конечно, это может быть неправильно, но оно работает.

Ответ 6

На высоком уровне у вас нет другого выбора, кроме как пройти весь словарь и посмотреть на каждое значение.

Может быть, это поможет: http://bytes.com/forum/thread563638.html Копирование/вставка от Джона Тимни:

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

Ответ 7

Вы никогда не сможете отсортировать словарь в любом случае. Они на самом деле не заказаны. Гарантии для словаря состоят в том, что наборы ключей и значений являются итеративными, а значения могут быть получены по индексу или ключу, но нет гарантии какого-либо конкретного порядка. Следовательно, вам нужно получить пару имя-значение в список.

Ответ 8

Вы не сортируете записи в словаре. Класс словаря в .NET реализуется как хэш-таблица - эта структура данных по определению не сортируется.

Если вам нужно иметь возможность перебирать свою коллекцию (по ключу), вам нужно использовать SortedDictionary, который реализован как двоичное дерево поиска.

В вашем случае, однако, структура источника не имеет значения, поскольку она сортируется по другому полю. Вам все равно придется сортировать его по частоте и помещать в новую коллекцию, отсортированную по соответствующему полю (частоте). Поэтому в этой коллекции частоты - это клавиши, а слова - значения. Поскольку многие слова могут иметь одинаковую частоту (и вы собираетесь использовать ее в качестве ключа), вы не можете использовать ни словарь, ни SortedDictionary (для них требуются уникальные ключи). Это оставляет вас с SortedList.

Я не понимаю, почему вы настаиваете на поддержании ссылки на исходный элемент в вашем основном/первом словаре.

Если объекты в вашей коллекции имели более сложную структуру (больше полей), и вам нужно было иметь возможность эффективно обращаться к ним/сортировать их с помощью нескольких разных полей в качестве ключей. Возможно, вам понадобится настраиваемая структура данных, которая будет состоять из основное хранилище, которое поддерживает O (1) вставку и удаление (LinkedList) и несколько структур индексирования - Словари/Сортированные словари/Сортированные списки. Эти индексы будут использовать одно из полей вашего сложного класса в качестве ключа и указатель/ссылку на LinkedListNode в LinkedList в качестве значения.

Вам нужно будет координировать вставки и удаления, чтобы синхронизировать индексы с основной коллекцией (LinkedList), и удаление было бы довольно дорогостоящим, я думаю. Это похоже на то, как работают индексы базы данных - они являются фантастическими для поиска, но они становятся бременем, когда вам нужно выполнять множество операций и удаления.

Все вышесказанное оправдано только в том случае, если вы собираетесь выполнять тяжелую обработку. Если вам нужно только вывести их после сортировки по частоте, вы можете просто создать список (анонимных) кортежей:

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

Ответ 9

Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);

Ответ 10

Или для удовольствия вы можете использовать некоторую доброту расширения 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));

Ответ 11

Сортировка значений

Показывает, как сортировать значения в словаре. Мы видим консольную программу, которую вы можете компилировать в Visual Studio и запускать. Он добавляет ключи к словарю, а затем сортирует их по их значениям. Помните, что экземпляры Dictionary первоначально не отсортированы. Мы используем ключевое слово ordering LINQ в запросе.

Пункт OrderBy Программа, которая сортирует словарь [С#]

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

Выход

dog: 0
cat: 1
programmer: 2
eel: 3
mouse: 5

Ответ 12

Сортировка списка SortedDictionary для привязки к элементу управления ListView с помощью 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>

Ответ 13

Самый простой способ получить отсортированный словарь - использовать встроенный класс 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 будет содержать отсортированную версию sections

Ответ 14

Другие ответы хороши, если все, что вам нужно, это иметь "временный" список, отсортированный по значению. Однако если вы хотите, чтобы словарь сортировался по Key который автоматически синхронизируется с другим словарем, отсортированным по Value, вы можете использовать Bijection<K1, K2>.

Bijection<K1, K2> позволяет вам инициализировать коллекцию с двумя существующими словарями, поэтому, если вы хотите, чтобы один из них не был отсортирован, а другой сортировался, вы можете создать свою биекцию с помощью кода, подобного

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

Вы можете использовать dict как любой обычный словарь (он реализует IDictionary<K, V>), а затем вызвать dict.Inverse чтобы получить "обратный" словарь, отсортированный по Value.

Bijection<K1, K2> является частью Loyc.Collections.dll, но если вы хотите, вы можете просто скопировать исходный код в ваш собственный проект.

Примечание. Если имеется несколько ключей с одинаковым значением, вы не можете использовать Bijection, но вы можете вручную синхронизировать обычный Dictionary<Key,Value> и BMultiMap<Value,Key>.

Ответ 15

Предположим, что у нас есть словарь как

   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) вы можете использовать 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);
        }

Ответ 16

На самом деле в С# словари dint имеют методы sort(), так как вас больше интересует сортировка по значениям, вы не можете получать значения до тех пор, пока не предоставите их ключ, короче говоря, вам нужно перебирать их, используя LINQ Order By,

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
}

ты можешь сделать один трюк,

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

или же

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

Это также зависит от того, какие ценности вы храните,
это один (например, string, int) или несколько (например, List, Array, пользовательский класс),
если вы одиноки, вы можете составить список, а затем применить сортировку.
если пользовательский класс, то этот класс должен реализовывать IComparable,
ClassName: IComparable<ClassName> и переопределяет compareTo(ClassName c) поскольку они работают быстрее, чем LINQ, и более объектно-ориентированы.

Ответ 17

Вы можете отсортировать словарь по значению и получить результат в словаре, используя следующий код:

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          

Ответ 18

Учитывая, что у вас есть словарь, вы можете сортировать его непосредственно по значениям, используя ниже один лайнер:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);