キーと値で構成される辞書を値でソートしなければならないことがよくあります。たとえば、単語とそれぞれの頻度のハッシュがあり、頻度で並べ替えます。
SortedList
単一の値(頻度など)に適したものがあり、それを単語にマッピングします。
SortedDictionaryは、値ではなくキーで並べ替えます。カスタムクラスに頼る人もいますが、よりクリーンな方法はありますか?
キーと値で構成される辞書を値でソートしなければならないことがよくあります。たとえば、単語とそれぞれの頻度のハッシュがあり、頻度で並べ替えます。
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));
myList.Sort((x,y)=>x.Value.CompareTo(y.Value));
IEnumerable
ので、次のようなソートされたリストを取得できます:var mySortedList = myDictionary.OrderBy(d => d.Value).ToList();
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
句も含めることができます。
IEnumerable<KeyValuePair<TKey, TValue>>
かOrderedDictionary<TKey, TValue>
。またはSortedDictionary
、最初からaを使用する必要があります。平野のためにDictionary
MSDNを明確に「の項目が返される順序が定義されていません。」述べています。@ rythos42の最新の編集に責任があるようです。:)
.ToDictionary
- 標準辞書はソート順を保証するものではありません
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の方法に似ています。
(for KeyValuePair<string, int> item in keywordCounts.OrderBy(key => key.Value) select item).ToDictionary(t => t.Key, t => t.Value)
-あなたの答え
辞書を値でソートし、それ自体に保存することができます(そのため、それをforeachすると、値が順番に表示されます)。
dict = dict.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
確かに、それは正しくないかもしれませんが、動作します。
高レベルでは、辞書全体を調べて各値を確認する以外に選択肢はありません。
多分これは役立つ: http ://bytes.com/forum/thread563638.html John 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);
}
);
とにかく辞書を並べ替えることはできません。実際には注文されていません。ディクショナリの保証は、キーと値のコレクションが反復可能であり、インデックスまたはキーによって値を取得できることですが、特定の順序は保証されていません。したがって、名前と値のペアをリストに入れる必要があります。
辞書のエントリは並べ替えません。.NETのディクショナリクラスはハッシュテーブルとして実装されます-このデータ構造は定義によりソートできません。
(キーで)コレクションを反復処理できるようにする必要がある場合は、バイナリ検索ツリーとして実装されているSortedDictionaryを使用する必要があります。
ただし、ソース構造は別のフィールドでソートされるため、ソース構造は関係ありません。それでも、頻度でソートして、関連するフィールド(頻度)でソートされた新しいコレクションに入れる必要があります。したがって、このコレクションでは、頻度はキーであり、単語は値です。多くの単語が同じ頻度を持つ可能性があるため(これをキーとして使用する予定)、DictionaryもSortedDictionaryも使用できません(一意のキーが必要です)。これにより、SortedListが残ります。
メイン/ファーストディクショナリの元のアイテムへのリンクを維持し続ける理由を理解できません。
コレクション内のオブジェクトがより複雑な構造(より多くのフィールド)を持ち、キーとしていくつかの異なるフィールドを使用してそれらに効率的にアクセス/ソートできるようにする必要がある場合-主ストレージで構成されるカスタムデータ構造がおそらく必要になりますO(1)の挿入と削除(LinkedList)といくつかのインデックス構造-Dictionaries / SortedDictionaries / SortedListsをサポートします。これらのインデックスは、複雑なクラスのフィールドの1つをキーとして使用し、LinkedList内のLinkedListNodeへのポインター/参照を値として使用します。
インデックスをメインコレクション(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);
}
VB.NETを使用SortedDictionary
してListView
コントロールにバインドするリストを並べ替えます。
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>
ソートされた辞書を取得する最も簡単な方法は、組み込み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
キーで並べ替えます。OPは値でソートする必要があります。 SortedDictionary
この場合は役に立ちません。
sorteddictionary()
常に少なくとも1マイクロ秒で勝ち取りました、そしてそれは管理するのがはるかに簡単です(それを辞書と同様に簡単に対話して管理するものに戻す変換のオーバーヘッドは0です(すでにですsorteddictionary
))。
値で並べ替えられた「一時的な」リストを作成するだけであれば、他の回答も適しています。ただし、によって並べ替えられたディクショナリを、によって並べ替えられKey
た別のディクショナリと自動的に同期させるValue
場合は、Bijection<K1, K2>
クラスを使用できます。
Bijection<K1, K2>
2つの既存のディクショナリでコレクションを初期化できるため、一方をソートせず、もう一方をソートしたい場合は、次のようなコードでバイジェクションを作成できます。
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#では、dictionaries 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
}
あなたは1つのトリックを行うことができ、
var sortedDictByOrder = items.OrderBy(v => v.Value);
または
var sortedKeys = from pair in dictName
orderby pair.Value ascending
select pair;
それは、格納している値の種類にも依存します。
単一(文字列、intなど)または複数(List、Array、ユーザー定義クラスなど)のいずれ
かで、単一のリストを作成してから並べ替えを適用できます。
ユーザー定義クラスの場合、そのクラスはIComparableを実装し
、LINQよりも高速でオブジェクト指向であるため
ClassName: IComparable<ClassName>
オーバーライドcompareTo(ClassName c)
する必要があります。
必要な名前空間: 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.
}
Ascによる注文:
foreach (KeyValuePair<string, int> kvp in counts.OrderBy(key => key.Value))
{
// some processing logic for each item if you want.
}
以下のコードを使用して、辞書を値でソートし、結果を辞書で取得できます。
Dictionary <<string, string>> ShareUserNewCopy =
ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
pair => pair.Value);
辞書がある場合、1つのライナーの下を使用して値で直接並べ替えることができます。
var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
IComparer
、トリックを実行するを作成することもできます(比較するためにキーを受け入れますが、キーを使用すると、値を取得できます)。;-)