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

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

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

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

Комментарии к вопросу (1)
Решение

Используйте:

using System.Linq.Enumerable;
...
List myList = aDictionary.ToList();

myList.Sort(
    delegate(KeyValuePair pair1,
    KeyValuePair 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));
Комментарии (11)

Используйте LINQ:

Dictionary myDict = new Dictionary();
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%, и т.д. Или если Вы используете свой индекс частотности слова для 'типа вперед', Вы могли бы также включать пункт 'StartsWith' также.

Комментарии (12)
var ordered = dict.OrderBy(x => x.Value);
Комментарии (9)

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

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

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

Комментарии (5)

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

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

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

Комментарии (8)

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

Возможно, это поможет: http://bytes.com/forum/thread563638.html Копирую/вставляю из Джона Тимни:

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

List myList = new List(s);
myList.Sort(
    delegate(KeyValuePair firstPair,
    KeyValuePair nextPair)
    {
        return firstPair.Value.CompareTo(nextPair.Value);
    }
);
Комментарии (2)

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

Комментарии (7)

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

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

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

Я don' t понимают, почему Вы настаиваете на том, чтобы поддерживать связь с оригинальным пунктом в Вашем главном/первом словаре.

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

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

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

var dict = new SortedDictionary();
// 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);
}
Комментарии (0)
Dictionary dic= new Dictionary();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
Комментарии (1)

Ценности вида

Это шоу, как сортировать ценности в Словаре. Мы видим программу пульта, которую Вы можете собрать в Визуальной Студии и пробеге. Это добавляет ключи к Словарю и затем сортирует их их ценностями. Помните, что случаи Словаря первоначально не сортированы ни в каком случае. Мы используем LINQ orderby ключевое слово в заявлении вопроса.

Пункт OrderBy Программа тот Словарь видов [C#]

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

class Program
{
    static void Main()
    {
        // Example dictionary.
        var dictionary = new Dictionary(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 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
Комментарии (0)

Или для забавы Вы могли использовать некоторое дополнительное совершенство LINQ:

var dictionary = new Dictionary { { "c", 3 }, { "a", 1 }, { "b", 2 } };
dictionary.OrderBy(x => x.Value)
  .ForEach(x => Console.WriteLine("{0}={1}", x.Key,x.Value));
Комментарии (0)

Сортировка '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:








Комментарии (0)

Самый легкий способ получить сортированный Словарь состоит в том, чтобы использовать построенный в классе 'SortedDictionary':

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

'sortedSections' будет содержать сортированную версию 'разделов'

Комментарии (3)

Другие ответы хороши, если у всего, что Вы хотите, должен быть " temporary" список сортирован Стоимостью. Однако, если Вы хотите сортировать словарь 'Ключом', что automatically synchronizes с другим словарем, который сортирован 'Стоимостью', Вы могли использовать ['Bijection< K1, K2&gt'; класс] (http://ecsharp.net/doc/code/classLoyc_1_1Collections_1_1Bijection.html).

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

var dict = new Bijection(new Dictionary(), 
                               new SortedDictionary());

Вы можете использовать 'dict' как любой нормальный словарь (это осуществляет 'IDictionary< K, V&gt';), и затем звонят 'dict. Инверсия', чтобы получить " inverse" словарь, который сортирован 'Стоимостью'.

'Bijection< K1, K2&gt'; часть [Loyc. Collections.dll] (http://core.loyc.net/), но если Вы хотите, Вы могли бы просто скопировать [исходный код] (https://github.com/qwertie/Loyc/blob/master/Core/Loyc. Collections/Other/Bijection.cs) в Ваш собственный проект.

Отметьте : В случае, если есть несколько ключей с той же стоимостью, Вы can' t используют 'Взаимно однозначное соответствие', но Вы могли вручную синхронизировать между обычным 'Dictionary< Ключ, Value&gt'; и ['BMultiMap< Стоимость, Key&gt';] (http://loyc.net/doc/code/classLoyc_1_1Collections_1_1BMultiMap_3_01K_00_01V_01_4.html).

Комментарии (1)

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

   Dictionary dict = new Dictionary();
   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. Вы можете использовать 'временный словарь, чтобы сохранить as' ценностей :
        Dictionary dctTemp = new Dictionary();

        foreach (KeyValuePair pair in dict.OrderBy(key => key.Value))
        {
            dctTemp .Add(pair.Key, pair.Value);
        }
Комментарии (0)

На самом деле в C#, у вмятины Словарей есть вид () методы, поскольку Вы больше интересуетесь видом ценностями, Вы наклоняетесь, получают ценности, пока Вы не обеспечиваете их ключевой, короче говоря, Вы должны повторить через них, использование LINQ' s Заказ,

var items = new Dictionary();
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;

также зависят от того, какие ценности Вы храните,
действительно ли это единственное (как последовательность, интервал) или несколько (как Список, Множество, пользователь определил класс),
если единственный Вы можете составить список его, тогда применяют вид.
если пользователь определил класс, тогда тот класс должен осуществить IComparable,
'ClassName: IComparable< ClassName&gt'; и отвергните 'compareTo (ClassName c)' поскольку они больше быстрее, чем LINQ и более объектно-ориентированные.

Комментарии (0)

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

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Комментарии (1)

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

Dictionary  ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
Комментарии (2)