C#で辞書を反復処理するいくつかの異なる方法を見てきました。標準的な方法はありますか?
31 に答える
foreach(KeyValuePair<string, string> entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
別の言語で連想配列を使用するように、C#で汎用辞書を使用しようとしている場合:
foreach(var item in myDictionary)
{
foo(item.Key);
bar(item.Value);
}
または、キーのコレクションを反復処理するだけでよい場合は、次を使用します。
foreach(var item in myDictionary.Keys)
{
foo(item);
}
そして最後に、値にのみ関心がある場合:
foreach(var item in myDictionary.Values)
{
foo(item);
}
(var
キーワードはオプションのC#3.0以降の機能であることに注意してください。ここでは、キー/値の正確なタイプを使用することもできます)
場合によっては、for ループの実装によって提供されるカウンターが必要になることがあります。そのために、LINQ はElementAt
以下を可能にするものを提供します。
for (int index = 0; index < dictionary.Count; index++) {
var item = dictionary.ElementAt(index);
var itemKey = item.Key;
var itemValue = item.Value;
}
キーと値のどちらを求めているかによって異なります...
MSDNDictionary(TKey, TValue)
クラスの説明から:
// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
Console.WriteLine("Key = {0}, Value = {1}",
kvp.Key, kvp.Value);
}
// To get the values alone, use the Values property.
Dictionary<string, string>.ValueCollection valueColl =
openWith.Values;
// The elements of the ValueCollection are strongly typed
// with the type that was specified for dictionary values.
Console.WriteLine();
foreach( string s in valueColl )
{
Console.WriteLine("Value = {0}", s);
}
// To get the keys alone, use the Keys property.
Dictionary<string, string>.KeyCollection keyColl =
openWith.Keys;
// The elements of the KeyCollection are strongly typed
// with the type that was specified for dictionary keys.
Console.WriteLine();
foreach( string s in keyColl )
{
Console.WriteLine("Key = {0}", s);
}
一般に、特定の文脈なしに「最良の方法」を尋ねる ことは、最良の色は何ですか?と尋ねるようなものです。
一方で、色はたくさんあり、最適な色はありません。それは必要に応じて異なり、多くの場合、味にも依存します。
一方、C# で Dictionary を反復処理するには多くの方法があり、最善の方法はありません。それは必要に応じて異なり、多くの場合、味にも依存します。
最も簡単な方法
foreach (var kvp in items)
{
// key is kvp.Key
doStuff(kvp.Value)
}
値のみが必要な場合(それを呼び出すことができitem
、より読みやすくなりkvp.Value
ます)。
foreach (var item in items.Values)
{
doStuff(item)
}
特定の並べ替え順序が必要な場合
一般に、初心者は Dictionary の列挙の順序に驚かれます。
LINQ は、順序 (および他の多くのもの) を指定できる簡潔な構文を提供します。たとえば、次のようになります。
foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
// key is kvp.Key
doStuff(kvp.Value)
}
ここでも、値のみが必要な場合があります。LINQ は、次の簡潔なソリューションも提供します。
- 値を直接反復します (それを呼び出すことができ
item
、より読みやすくなりkvp.Value
ます) - しかし、キーでソートされています
ここにあります:
foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
doStuff(item)
}
これらの例から実行できる実際の使用例は他にもたくさんあります。特定の順序が必要ない場合は、「最も簡単な方法」 (上記を参照) に従ってください。
foreach
それは明らかにあなたが探しているものに依存しますが、私はそれが標準的な方法だと思います
foreach(var kvp in my_dictionary) {
...
}
それはあなたが探しているものですか?
マルチスレッド処理用の大きな辞書でこれを試すこともできます。
dictionary
.AsParallel()
.ForAll(pair =>
{
// Process pair.Key and pair.Value here
});
この質問にはすでに多くの回答が寄せられていることに感謝していますが、少し調査を行いたいと思いました。
辞書の反復処理は、配列などの反復処理と比較すると、かなり遅くなる可能性があります。私のテストでは、配列の反復には 0.015003 秒かかりましたが、辞書 (要素数が同じ) の反復には 0.0365073 秒かかりました。これは 2.4 倍の長さです! 私ははるかに大きな違いを見てきましたが。比較のために、List は 0.00215043 秒の間のどこかにありました。
しかし、それはリンゴとミカンを比較するようなものです。私のポイントは、辞書の反復処理が遅いということです。
辞書はルックアップ用に最適化されているため、それを念頭に置いて 2 つのメソッドを作成しました。1 つは単純に foreach を実行し、もう 1 つはキーを反復して検索します。
public static string Normal(Dictionary<string, string> dictionary)
{
string value;
int count = 0;
foreach (var kvp in dictionary)
{
value = kvp.Value;
count++;
}
return "Normal";
}
これはキーをロードし、代わりにそれらを繰り返し処理します (キーを string[] にプルしようとしましたが、違いはごくわずかでした。
public static string Keys(Dictionary<string, string> dictionary)
{
string value;
int count = 0;
foreach (var key in dictionary.Keys)
{
value = dictionary[key];
count++;
}
return "Keys";
}
この例では、通常の foreach テストは 0.0310062 かかり、キー バージョンは 0.2205441 かかりました。すべてのキーをロードし、すべてのルックアップを反復処理すると、明らかに大幅に遅くなります!
最終テストとして、ここでキーを使用する利点があるかどうかを確認するために、反復を 10 回実行しました (この時点で、私はただ興味がありました)。
何が起こっているかを視覚化するのに役立つ場合は、RunTest メソッドを次に示します。
private static string RunTest<T>(T dictionary, Func<T, string> function)
{
DateTime start = DateTime.Now;
string name = null;
for (int i = 0; i < 10; i++)
{
name = function(dictionary);
}
DateTime end = DateTime.Now;
var duration = end.Subtract(start);
return string.Format("{0} took {1} seconds", name, duration.TotalSeconds);
}
ここでは、通常の foreach の実行に 0.2820564 秒かかりました (予想どおり、1 回の反復にかかる時間の約 10 倍の長さです)。キーの反復には 2.2249449 秒かかりました。
追加する編集: 他の回答のいくつかを読んで、辞書の代わりに辞書を使用するとどうなるか疑問に思いました. この例では、配列に 0.0120024 秒、リストに 0.0185037 秒、辞書に 0.0465093 秒かかりました。データ型がディクショナリの速度に違いをもたらすと期待するのは妥当です。
私の結論は何ですか?
- 可能であれば、辞書を反復することは避けてください。同じデータを含む配列を反復するよりも大幅に遅くなります。
- ディクショナリを反復することを選択した場合は、あまり賢くしようとしないでください。ただし、標準の foreach メソッドを使用するよりもはるかに悪い結果になる可能性があります。
たくさんのオプションがあります。私の個人的なお気に入りはKeyValuePairによるものです
Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here
foreach (KeyValuePair<string,object> kvp in myDictionary)
{
// Do some interesting things
}
キーと値のコレクションを使用することもできます
繰り返すことを以下に提案しました
Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here
foreach (KeyValuePair<string,object> kvp in myDictionary) {
//Do some interesting things;
}
参考までにforeach
、値がオブジェクト型の場合は機能しません。
MSDN の DictionaryBase クラスのドキュメントでこのメソッドを見つけました。
foreach (DictionaryEntry de in myDictionary)
{
//Do some stuff with de.Value or de.Key
}
これは、DictionaryBase から継承したクラスで正しく機能することができた唯一のものでした。
列挙する値だけが必要な場合は、ディクショナリの値コレクションを使用します。
foreach(var value in dictionary.Values)
{
// do something with entry.Value only
}
これが最速の方法であると述べているこの投稿で報告されています: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html
たとえば、デフォルトで値コレクションを反復処理する場合は、IEnumerable <>を実装できると思います。ここで、Tはディクショナリ内の値オブジェクトのタイプであり、「this」はディクショナリです。
public new IEnumerator<T> GetEnumerator()
{
return this.Values.GetEnumerator();
}
C# でディクショナリを反復処理する方法はいくつかありますが、私が見つけた最良かつ最も簡単な方法はforeachを使用することです。
foreach(KeyValuePair<string, string> entry in mDictionary)
{
// Your coding for Value & Key ...
}
var dictionary = new Dictionary<string, int>
{
{ "Key", 12 }
};
var aggregateObjectCollection = dictionary.Select(
entry => new AggregateObject(entry.Key, entry.Value));
ほとんどの回答はforeach-loopに関連しているため、2セントを追加したかっただけです。次のコードを見てください。
Dictionary<String, Double> myProductPrices = new Dictionary<String, Double>();
//Add some entries to the dictionary
myProductPrices.ToList().ForEach(kvP =>
{
kvP.Value *= 1.15;
Console.Writeline(String.Format("Product '{0}' has a new price: {1} $", kvp.Key, kvP.Value));
});
これにより「.ToList()」の追加呼び出しが追加されますが、パフォーマンスがわずかに向上する可能性があります (ここで指摘されているようにforeach vs someList.Foreach(){} )。オプション / はまったく効果がありません。
また、foreach ループ内で「Value」プロパティに値を割り当てることはできないことに注意してください。一方、「キー」も操作できるため、実行時に問題が発生する可能性があります。
キーと値を「読み取る」だけの場合は、IEnumerable.Select() を使用することもできます。
var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );