Вопрос

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

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

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

Это было полезно?

Решение

Использовать:

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

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

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

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

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

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

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

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

Возможно, это поможет: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));

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

Здесь показано, как сортировать значения в словаре.Мы видим консольную программу, которую можно скомпилировать в Visual Studio и запустить.Он добавляет ключи в словарь, а затем сортирует их по значениям.Помните, что экземпляры Dictionary изначально никак не сортируются.Мы используем ключевое слово 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

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

КСАМЛ:

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

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

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

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

На самом деле в C#, Dictionares Dint имеет методы Sort (), так как вы больше заинтересованы в сортировке по значениям, вы не можете получить значения, пока не предоставите им ключ, короче говоря, вам необходимо итерацию через них, используя порядок LINQ 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;

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

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

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);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top