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

голоса
671

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

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

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

Задан 02/08/2008 в 01:40
источник пользователем
На других языках...                            


17 ответов

голоса
473

Использование 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положение , а также.

Ответил 04/08/2008 d 16:22
источник пользователем

голоса
459

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

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));
Ответил 02/08/2008 d 02:15
источник пользователем

голоса
179
var ordered = dict.OrderBy(x => x.Value);
Ответил 11/11/2010 d 18:16
источник пользователем

голоса
148

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

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

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

Ответил 02/08/2008 d 01:43
источник пользователем

голоса
140

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

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

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

Ответил 22/06/2011 d 11:26
источник пользователем

голоса
56

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

Может быть , это помогает: http://bytes.com/forum/thread563638.html Copy / Оклейка от Джона 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);
    }
);
Ответил 02/08/2008 d 01:47
источник пользователем

голоса
22

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

Ответил 19/12/2008 d 23:47
источник пользователем

голоса
16

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

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

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

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

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

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

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

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);
}
Ответил 13/12/2012 d 07:19
источник пользователем

голоса
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);
Ответил 20/07/2015 d 11:01
источник пользователем

голоса
10

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

Это показывает, как сортировать значения в словаре. Мы видим консольную программу можно компилировать в Visual Studio и запустить. Он добавляет ключи к словарю, а затем сортирует их по их значениям. Помните, что словарь экземпляры изначально не отсортированы в любом случае. Мы используем ключевое слово OrderBy 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
Ответил 20/07/2012 d 10:49
источник пользователем

голоса
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));
Ответил 30/06/2010 d 12:12
источник пользователем

голоса
9

Сортировка 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>
Ответил 23/04/2010 d 10:36
источник пользователем

голоса
5

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

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

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

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

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

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

Ответил 26/02/2016 d 07:15
источник пользователем

голоса
5

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

Ответил 02/04/2010 d 23:36
источник пользователем

голоса
4

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

   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);
        }
Ответил 02/02/2015 d 10:46
источник пользователем

голоса
-2

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

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Ответил 31/05/2014 d 23:30
источник пользователем

голоса
-2

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

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
Ответил 24/07/2012 d 13:24
источник пользователем

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