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

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

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

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

23 ответа

Решение

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

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

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

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

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

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

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

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

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

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

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

Может быть, это поможет: 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);
    }
);

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

Вы не сортируете записи в Словаре. Класс словаря в.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);
}
Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);

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

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

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

Это показывает, как сортировать значения в словаре. Мы видим консольную программу, которую вы можете скомпилировать в 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

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

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

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

или же

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

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

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

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

Требуемое пространство имен: using System.Linq;

Dictionary<string, int> counts = new Dictionary<string, int>();
counts.Add("one", 1);
counts.Add("four", 4);
counts.Add("two", 2);
counts.Add("three", 3);

Сортировать по убыванию:

foreach (KeyValuePair<string, int> kvp in counts.OrderByDescending(key => key.Value))
{
// some processing logic for each item if you want.
}

Заказ по возрастанию:

foreach (KeyValuePair<string, int> kvp in counts.OrderBy(key => key.Value))
{
// some processing logic for each item if you want.
}

Следующий фрагмент кода сортирует словарь по значениям.

Код сначала создает словарь, а затем используетOrderByспособ сортировки предметов.

      public void SortDictionary()  
{  
  
    // Create a dictionary with string key and Int16 value pair  
    Dictionary<string, Int16> AuthorList = new Dictionary<string, Int16>();  
    AuthorList.Add("Mahesh Chand", 35);  
    AuthorList.Add("Mike Gold", 25);  
    AuthorList.Add("Praveen Kumar", 29);  
    AuthorList.Add("Raj Beniwal", 21);  
    AuthorList.Add("Dinesh Beniwal", 84);   
  
    // Sorted by Value  
  
    Console.WriteLine("Sorted by Value");  
    Console.WriteLine("=============");  
    foreach (KeyValuePair<string, Int16> author in AuthorList.OrderBy(key => key.Value))  
    {  
        Console.WriteLine("Key: {0}, Value: {1}", author.Key, author.Value);  
    }  
} 

Сортировка и печать:

var items = from pair in players_Dic
                orderby pair.Value descending
                select pair;

// Display results.
foreach (KeyValuePair<string, int> pair in items)
{
    Debug.Log(pair.Key + " - " + pair.Value);
}

Измените нисходящий на восходящий, чтобы изменить порядок сортировки

Словарь по определению представляет собой неупорядоченную ассоциативную структуру, которая содержит только значения и ключи в хешируемом виде. Другими словами, не имеет предвидимого способа заказать словарь.

Для справки прочитайте эту статью на языке python.

Связать структуры данных Python

Лучший способ:

      var list = dict.Values.OrderByDescending(x => x).ToList();
var sortedData = dict.OrderBy(x => list.IndexOf(x.Value));

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

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

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

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Другие вопросы по тегам