Как вы сортируете словарь по значению? - PullRequest
742 голосов
/ 02 августа 2008

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

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

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

Ответы [ 18 ]

499 голосов
/ 04 августа 2008

Использовать 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.

498 голосов
/ 02 августа 2008

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

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));
212 голосов
/ 11 ноября 2010
var ordered = dict.OrderBy(x => x.Value);
156 голосов
/ 02 августа 2008

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

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

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

150 голосов
/ 22 июня 2011

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

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

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

58 голосов
/ 02 августа 2008

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

Может быть, это поможет: 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);
    }
);
23 голосов
/ 20 декабря 2008

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

16 голосов
/ 13 декабря 2012

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

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

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

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

Если объекты в вашей коллекции имеют более сложную структуру (больше полей), и вам необходимо иметь возможность эффективно обращаться к ним / сортировать их, используя несколько различных полей в качестве ключей - вам, вероятно, понадобится настраиваемая структура данных, состоящая из основное хранилище, которое поддерживает вставку и удаление O (1) (LinkedList) и несколько структур индексирования - Словари / SortedDictionaries / SortedLists. Эти индексы будут использовать одно из полей вашего сложного класса в качестве ключа и указатель / ссылку на 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);
}
14 голосов
/ 20 июля 2015
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 голосов
/ 20 июля 2012

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

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

Порядок заказа Программа, которая сортирует словарь [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;
    }
}

выход

dog: 0
cat: 1
programmer: 2
eel: 3
mouse: 5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...