Вопрос:

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

c# .net sorting dictionary

523661 просмотра

18 ответа

10920 Репутация автора

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

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

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

Автор: Kalid Источник Размещён: 02.08.2008 12:40

Ответы (18)


157 плюса

10920 Репутация автора

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

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

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

Автор: Kalid Размещён: 02.08.2008 12:43

59 плюса

117105 Репутация автора

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

Может быть, это поможет: 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);
    }
);
Автор: Michael Stum Размещён: 02.08.2008 12:47

491 плюса

17761 Репутация автора

Решение

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

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));
Автор: Leon Bambrick Размещён: 02.08.2008 01:15

495 плюса

6275 Репутация автора

Используйте 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предложение.

Автор: caryden Размещён: 04.08.2008 03:22

23 плюса

1183 Репутация автора

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

Автор: Roger Willcocks Размещён: 19.12.2008 10:47

5 плюса

83 Репутация автора

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

Автор: Alex Ruiz Размещён: 02.04.2010 10:36

9 плюса

4002 Репутация автора

Сортировка 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>
Автор: BSalita Размещён: 23.04.2010 09:36

10 плюса

118585 Репутация автора

Или для удовольствия вы можете использовать некоторые расширения 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));
Автор: mythz Размещён: 30.06.2010 11:12

201 плюса

5677 Репутация автора

var ordered = dict.OrderBy(x => x.Value);
Автор: sean Размещён: 11.11.2010 05:16

147 плюса

35142 Репутация автора

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

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

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

Автор: Matt Frear Размещён: 22.06.2011 10:26

10 плюса

2701 Репутация автора

Сортировать значения

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

OrderBy Clause Программа, которая сортирует словарь [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
Автор: lasitha edirisooriya Размещён: 20.07.2012 09:49

-2 плюса

29 Репутация автора

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

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
Автор: pawan Kumar Размещён: 24.07.2012 12:24

16 плюса

4131 Репутация автора

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

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

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

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

Если объекты в вашей коллекции имеют более сложную структуру (больше полей) и вам необходимо иметь возможность эффективно обращаться к ним / сортировать их, используя несколько различных полей в качестве ключей - вам, вероятно, понадобится настраиваемая структура данных, которая будет состоять из основного хранилища, которое поддерживает вставку и удаление O (1) (LinkedList) и несколько структур индексирования - Dictionaries / 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);
}
Автор: Zar Shardan Размещён: 13.12.2012 06:19

-2 плюса

1527 Репутация автора

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

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Автор: aggaton Размещён: 31.05.2014 10:30

3 плюса

107 Репутация автора

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

   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);
        }
Автор: Akshay Kapoor Размещён: 02.02.2015 10:46

13 плюса

512 Репутация автора

Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
Автор: mrfazolka Размещён: 20.07.2015 11:01

5 плюса

8119 Репутация автора

Другие ответы хороши, если все, что вам нужно, это иметь «временный» список, отсортированный по значению. Однако, если вы хотите, чтобы словарь, отсортированный по ним 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>и a BMultiMap<Value,Key>.

Автор: Qwertie Размещён: 26.02.2016 07:15

0 плюса

720 Репутация автора

На самом деле в C # словари 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);

Он также зависит от того, какие значения вы сохраняете
: одиночные (например, string, int) или множественные (например, List, Array),
если вы можете создать единый список, то примените sort.

Автор: Ashish Kamble Размещён: 26.02.2019 12:39
32x32