Мне часто приходится сортировать словарь, состоящий из ключей и значений, по значению. Например, у меня есть хеш слов и соответствующих частот, которые я хочу заказать по частоте.
Существует SortedList
, который хорош для одного значения (например, частоты), что я хочу отнести его к слову.
SortedDictionary заказывает ключ, а не значение. Некоторые прибегают к пользовательскому классу, но есть ли более чистый способ?
Использование:
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);
Оглядываясь и используя некоторые функции С# 3.0, мы можем это сделать:
foreach (KeyValuePair<string,int> item in keywordCounts.OrderBy(key=> key.Value))
{
// do something with item.Key and item.Value
}
Это самый чистый способ, который я видел и похож на рубиновый способ обработки хэшей.
Вы можете сортировать словарь по значению и сохранять его обратно в себя (так что, когда вы его просматриваете, значения выходят в порядок):
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, который реализован как двоичное дерево поиска.
В вашем случае, однако, структура источника не имеет значения, поскольку она сортируется по другому полю. Вам все равно придется сортировать его по частоте и помещать в новую коллекцию, отсортированную по соответствующему полю (частоте). Поэтому в этой коллекции частоты - это клавиши, а слова - значения. Поскольку многие слова могут иметь одинаковую частоту (и вы собираетесь использовать ее в качестве ключа), вы не можете использовать ни словарь, ни SortedDictionary (для них требуются уникальные ключи). Это оставляет вас с SortedList.
Я не понимаю, почему вы настаиваете на поддержании ссылки на исходный элемент в вашем основном/первом словаре.
Если объекты в вашей коллекции имели более сложную структуру (больше полей), и вам нужно было иметь возможность эффективно обращаться к ним/сортировать их с помощью нескольких разных полей в качестве ключей. Возможно, вам понадобится настраиваемая структура данных, которая будет состоять из основное хранилище, которое поддерживает O (1) вставку и удаление (LinkedList) и несколько структур индексирования - Словари/Сортированные словари/Сортированные списки. Эти индексы будут использовать одно из полей вашего сложного класса в качестве ключа и указатель/ссылку на 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);
Сортировка значений
Показывает, как сортировать значения в словаре. Мы видим консольную программу, которую вы можете компилировать в Visual Studio и запускать. Он добавляет ключи к словарю, а затем сортирует их по их значениям. Помните, что экземпляры Dictionary первоначально не отсортированы. Мы используем ключевое слово ordering LINQ в запросе.
Пункт OrderBy Программа, которая сортирует словарь [С#]
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
Или для удовольствия вы можете использовать некоторую доброту расширения 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>
Другие ответы хороши, если все, что вы хотите, это иметь "временный" список, отсортированный по значению. Однако, если вы хотите иметь словарь, отсортированный по 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>
и a BMultiMap<Value,Key>
.
Самый простой способ получить отсортированный словарь - использовать встроенный класс 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
SortedDictionary
сортирует по ключам. ОП хочет отсортировать по значению. SortedDictionary
не помогает в этом случае.
sorteddictionary()
время выполнения операций и sorteddictionary()
всегда выигрывал по крайней мере на 1 микросекунду, и им намного легче управлять (поскольку издержки преобразования его обратно во что-то, с чем легко взаимодействовать и управлять им, как в словаре, sorteddictionary
0 (это уже sorteddictionary
)).
Предположим, что у нас есть словарь как
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);
}
Учитывая, что у вас есть словарь, вы можете сортировать его непосредственно по значениям, используя ниже один лайнер:
var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Вы можете отсортировать словарь по значению и получить результат в словаре, используя следующий код:
Dictionary <<string, string>> ShareUserNewCopy =
ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
pair => pair.Value);
IComparer
который выполняет своюIComparer
(правда, он принимает ключ для сравнения, но с ключом вы можете получить значение). ;-)