ฉันเห็นวิธีต่าง ๆ ในการทำซ้ำพจนานุกรมใน C # มีวิธีมาตรฐานหรือไม่
ฉันเห็นวิธีต่าง ๆ ในการทำซ้ำพจนานุกรมใน C # มีวิธีมาตรฐานหรือไม่
คำตอบ:
foreach(KeyValuePair<string, string> entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
var entry
ดีกว่าในกรณีนั้นและดังนั้นฉันจึงโหวตคำตอบนี้ในการค้นหาครั้งที่สองแทนที่จะใช้คำตอบข้างต้น
var
เมื่อคุณไม่ทราบว่าประเภทนี้เป็นแนวปฏิบัติที่ไม่ดี
var
ทำงานเฉพาะในกรณีที่รู้ว่ารวบรวมในเวลารวบรวม ถ้า Visual Studio รู้ประเภทแล้วก็พร้อมให้คุณค้นหาเช่นกัน
หากคุณกำลังพยายามใช้พจนานุกรมทั่วไปใน 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 และสูงกว่าคุณยังสามารถใช้ประเภท / คีย์ที่แน่นอนได้ที่นี่)
myDictionary
(ยกเว้นว่าเป็นชื่อจริงของหลักสูตร) ฉันคิดว่าการใช้ var เป็นสิ่งที่ดีเมื่อประเภทชัดเจนเช่นvar x = "some string"
แต่เมื่อไม่ชัดเจนทันทีฉันคิดว่ามันเป็นโค้ดที่ขี้เกียจที่ทำร้ายผู้อ่าน / ผู้ตรวจสอบรหัส
var
ควรใช้เท่าที่จำเป็นในความคิดของฉัน โดยเฉพาะอย่างยิ่งที่นี่ไม่สร้างสรรค์: ประเภทKeyValuePair
นี้มีแนวโน้มที่เกี่ยวข้องกับคำถาม
var
มีจุดประสงค์ที่ไม่เหมือนใครและฉันไม่เชื่อว่ามันจะเป็น 'น้ำตาล' syntactic การใช้อย่างตั้งใจเป็นวิธีการที่เหมาะสม
ในบางกรณีคุณอาจต้องมีตัวนับที่อาจได้รับจากการใช้งาน for-loop สำหรับการที่ LINQ ให้ElementAt
ซึ่งช่วยให้ต่อไปนี้:
for (int index = 0; index < dictionary.Count; index++) {
var item = dictionary.ElementAt(index);
var itemKey = item.Key;
var itemValue = item.Value;
}
ElementAt
O (n) การดำเนินงาน?
.ElementAt
ในบริบทนี้อาจนำไปสู่ข้อบกพร่องเล็กน้อย ร้ายแรงยิ่งกว่านั้นคือประเด็นของอาร์ตูโรข้างต้น คุณจะต้องทำซ้ำdictionary.Count + 1
เวลาในพจนานุกรมที่นำไปสู่ความซับซ้อน O (n ^ 2) สำหรับการดำเนินการที่ควรเป็น O (n) เท่านั้น หากคุณต้องการดัชนีจริงๆ (ถ้าคุณทำคุณอาจใช้ประเภทการรวบรวมที่ไม่ถูกต้องในตอนแรก) คุณควรทำซ้ำdictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})
แทนและไม่ใช้.ElementAt
ภายในลูป
ขึ้นอยู่กับว่าคุณอยู่หลังคีย์หรือค่า ...
จากDictionary(TKey, TValue)
คำอธิบายคลาสMSDN :
// 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 # และไม่มีวิธีที่ดีที่สุด ขึ้นอยู่กับความต้องการและบ่อยครั้งที่รสนิยมเช่นกัน
foreach (var kvp in items)
{
// key is kvp.Key
doStuff(kvp.Value)
}
หากคุณต้องการเฉพาะค่า (อนุญาตให้เรียกว่าitem
สามารถอ่านได้มากกว่าkvp.Value
)
foreach (var item in items.Values)
{
doStuff(item)
}
โดยทั่วไปผู้เริ่มต้นจะประหลาดใจเกี่ยวกับลำดับการนับของพจนานุกรม
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)
}
มีกรณีการใช้งานจริงอีกมากมายที่คุณสามารถทำได้จากตัวอย่างเหล่านี้ หากคุณไม่ต้องการคำสั่งซื้อที่เฉพาะเจาะจงเพียงทำตาม "วิธีที่ตรงไปตรงมาที่สุด" (ดูด้านบน)!
.Values
และไม่ใช่ประโยคที่เลือก
Value
ฟิลด์ IOrderedEnumerable<KeyValuePair<TKey, TValue>>
ชนิดที่แน่นอนผมเห็นที่นี่เป็น บางทีคุณอาจหมายถึงอย่างอื่น? คุณช่วยเขียนบรรทัดที่สมบูรณ์ที่แสดงความหมายของคุณ (และทดสอบ) ได้ไหม?
items.Value
เหมือนที่คุณแนะนำ ในกรณีของส่วนที่สี่ที่คุณแสดงความคิดเห็นSelect()
เป็นวิธีที่ทำให้เกิดforeach
การระบุโดยตรงในค่าในพจนานุกรมแทนคู่ของคีย์ - ค่า ถ้าอย่างใดที่คุณไม่ชอบSelect()
ในกรณีนี้คุณอาจต้องการส่วนรหัสที่สาม จุดของส่วนที่สี่คือการแสดงว่าสามารถประมวลผลคอลเลกชันล่วงหน้าด้วย LINQ
.Keys.Orderby()
คุณจะทำซ้ำในรายการของคีย์ ถ้านั่นคือทั้งหมดที่คุณต้องการ หากคุณต้องการค่าจากนั้นในลูปคุณจะต้องค้นหาพจนานุกรมในแต่ละคีย์เพื่อรับค่า ในหลาย ๆ สถานการณ์มันจะไม่สร้างความแตกต่างในทางปฏิบัติ ในสถานการณ์ที่มีประสิทธิภาพสูงมันจะ เช่นเดียวกับที่ฉันเขียนในตอนต้นของคำตอบ: "มีหลายวิธี (... ) และไม่มีวิธีที่ดีที่สุดมันขึ้นอยู่กับความต้องการและบ่อยครั้งเกี่ยวกับรสนิยมด้วย"
ฉันจะบอกว่า foreach เป็นวิธีมาตรฐานถึงแม้ว่ามันจะขึ้นอยู่กับสิ่งที่คุณกำลังมองหา
foreach(var kvp in my_dictionary) {
...
}
นั่นคือสิ่งที่คุณกำลังมองหา?
kvp
เป็นที่นิยมใช้ในการตั้งชื่ออินสแตนซ์ KeyValuePair เมื่อ iterating foreach(var kvp in myDictionary){...
กว่าพจนานุกรมและโครงสร้างข้อมูลที่เกี่ยวข้อง:
คุณสามารถลองใช้พจนานุกรมนี้เพื่อการประมวลผลแบบมัลติเธรด
dictionary
.AsParallel()
.ForAll(pair =>
{
// Process pair.Key and pair.Value here
});
C # 7.0แนะนำDeconstructorsและถ้าคุณใช้ . NET Core 2.0 ขึ้นไปแอพ structKeyValuePair<>
จะมีDeconstruct()
ให้คุณแล้ว ดังนั้นคุณสามารถทำได้:
var dic = new Dictionary<int, string>() { { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
foreach (var (key, value) in dic) {
Console.WriteLine($"Item [{key}] = {value}");
}
//Or
foreach (var (_, value) in dic) {
Console.WriteLine($"Item [NO_ID] = {value}");
}
//Or
foreach ((int key, string value) in dic) {
Console.WriteLine($"Item [{key}] = {value}");
}
foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
ฉันขอขอบคุณคำถามนี้มีคำตอบจำนวนมากอยู่แล้ว แต่ฉันต้องการที่จะทำวิจัยเล็กน้อย
การวนซ้ำพจนานุกรมอาจช้ากว่าเมื่อเปรียบเทียบกับการวนซ้ำบางอย่างเช่นอาร์เรย์ ในการทดสอบของฉันการวนซ้ำในอาร์เรย์ใช้เวลา 0.015003 วินาทีในขณะที่การวนซ้ำในพจนานุกรม (ด้วยจำนวนองค์ประกอบเท่ากัน) ใช้เวลา 0.0365073 วินาทีนั่นคือ 2.4 เท่า! แม้ว่าฉันจะเห็นความแตกต่างที่ใหญ่กว่ามาก สำหรับการเปรียบเทียบรายการอยู่ในระหว่างเวลา 0.00215043 วินาที
อย่างไรก็ตามนั่นก็เหมือนกับการเปรียบเทียบแอปเปิ้ลกับส้ม ประเด็นของฉันคือการวนซ้ำในพจนานุกรมช้า
พจนานุกรมได้รับการปรับให้เหมาะกับการค้นหาดังนั้นเมื่อคำนึงถึงสิ่งที่ฉันได้สร้างไว้สองวิธี คนหนึ่งทำหน้าที่คนอื่น ๆ ทำซ้ำปุ่มอื่น ๆ ก็จะค้นหาขึ้นมา
public static string Normal(Dictionary<string, string> dictionary)
{
string value;
int count = 0;
foreach (var kvp in dictionary)
{
value = kvp.Value;
count++;
}
return "Normal";
}
อันนี้โหลดกุญแจแล้ววนซ้ำมันแทน (ฉันลองดึงกุญแจเข้าไปในสายอักขระ [] แต่ความแตกต่างนั้นเล็กน้อยมาก
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 การโหลดกุญแจทั้งหมดและวนซ้ำในการค้นหาทั้งหมดนั้นช้ากว่ามากอย่างเห็นได้ชัด!
สำหรับการทดสอบครั้งสุดท้ายฉันทำซ้ำอีกสิบครั้งเพื่อดูว่ามีประโยชน์กับการใช้ปุ่มที่นี่ (โดยจุดนี้ฉันแค่อยากรู้อยากเห็น):
นี่คือวิธี 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);
}
ที่นี่การวิ่งปกติแต่ละครั้งใช้เวลา 0.2820564 วินาที (นานกว่าการทำซ้ำครั้งเดียวประมาณสิบเท่า - ตามที่คุณคาดหวัง) การวนซ้ำของคีย์ใช้เวลา 2.2249449 วินาที
แก้ไขเพื่อเพิ่ม: การ อ่านคำตอบอื่น ๆ ทำให้ฉันถามว่าจะเกิดอะไรขึ้นถ้าฉันใช้พจนานุกรมแทนพจนานุกรม ในตัวอย่างนี้อาร์เรย์ใช้เวลา 0.0120024 วินาทีรายการ 0.0185037 วินาทีและพจนานุกรม 0.0465093 วินาที มีความสมเหตุสมผลที่จะคาดหวังว่าชนิดข้อมูลจะสร้างความแตกต่างว่าพจนานุกรมจะทำงานช้าลงเท่าใด
บทสรุปของฉันคืออะไร
มีตัวเลือกมากมาย รายการโปรดส่วนตัวของฉันคือ KeyValuePair
Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here
foreach (KeyValuePair<string,object> kvp in myDictionary)
{
// Do some interesting things
}
คุณยังสามารถใช้ชุดกุญแจและค่าได้
ด้วย.NET Framework 4.7
หนึ่งสามารถใช้การสลายตัว
var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
Console.WriteLine(fruit + ": " + number);
}
ในการทำให้โค้ดนี้ใช้งานในเวอร์ชัน C # ที่ต่ำกว่าให้เพิ่มSystem.ValueTuple NuGet package
และเขียนที่ใดที่หนึ่ง
public static class MyExtensions
{
public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple,
out T1 key, out T2 value)
{
key = tuple.Key;
value = tuple.Value;
}
}
ValueTuple
ในตัวมันมีให้ในรูปแบบแพ็คเกจ nuget สำหรับเวอร์ชั่นก่อนหน้านี้ ที่สำคัญกว่า, C # 7.0 ขึ้นไปเป็นสิ่งจำเป็นสำหรับDeconstruct
วิธีการในการทำงานเป็น Deconstructor var (fruit, number) in fruits
สำหรับ
ตั้งแต่ C # 7 คุณสามารถแยกโครงสร้างวัตถุเป็นตัวแปรได้ ฉันเชื่อว่านี่เป็นวิธีที่ดีที่สุดในการทำซ้ำพจนานุกรม
ตัวอย่าง:
สร้างวิธีการขยายKeyValuePair<TKey, TVal>
ที่ deconstructs มัน:
public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey key, out TVal value)
{
key = pair.Key;
value = pair.Value;
}
วนซ้ำDictionary<TKey, TVal>
ในลักษณะต่อไปนี้
// Dictionary can be of any types, just using 'int' and 'string' as examples.
Dictionary<int, string> dict = new Dictionary<int, string>();
// Deconstructor gets called here.
foreach (var (key, value) in dict)
{
Console.WriteLine($"{key} : {value}");
}
คุณแนะนำด้านล่างเพื่อย้ำ
Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here
foreach (KeyValuePair<string,object> kvp in myDictionary) {
//Do some interesting things;
}
FYI foreach
ไม่ทำงานหากค่าเป็นประเภทวัตถุ
foreach
จะไม่ทำงานหากที่คุ้มค่าเป็นประเภทobject
? มิฉะนั้นสิ่งนี้ไม่สมเหตุสมผล
รูปแบบที่ง่ายที่สุดในการย้ำพจนานุกรม:
foreach(var item in myDictionary)
{
Console.WriteLine(item.Key);
Console.WriteLine(item.Value);
}
ใช้C # 7เพิ่มวิธีการขยายนี้ไปยังโครงการใด ๆ ของการแก้ปัญหาของคุณ:
public static class IDictionaryExtensions
{
public static IEnumerable<(TKey, TValue)> Tuples<TKey, TValue>(
this IDictionary<TKey, TValue> dict)
{
foreach (KeyValuePair<TKey, TValue> kvp in dict)
yield return (kvp.Key, kvp.Value);
}
}
และใช้ไวยากรณ์ง่าย ๆ นี้
foreach (var(id, value) in dict.Tuples())
{
// your code using 'id' and 'value'
}
หรืออันนี้ถ้าคุณต้องการ
foreach ((string id, object value) in dict.Tuples())
{
// your code using 'id' and 'value'
}
ในสถานที่ดั้งเดิม
foreach (KeyValuePair<string, object> kvp in dict)
{
string id = kvp.Key;
object value = kvp.Value;
// your code using 'id' and 'value'
}
วิธีการขยายเปลี่ยนส่วนที่KeyValuePair
คุณIDictionary<TKey, TValue>
พิมพ์เป็นอย่างมากtuple
ช่วยให้คุณใช้ไวยากรณ์ที่สะดวกสบายใหม่นี้
มันแปลง - เพียง - รายการพจนานุกรมที่ต้องการเป็นtuples
ดังนั้นจึงไม่แปลงทั้งพจนานุกรมเป็นtuples
ดังนั้นจึงไม่มีความกังวลเกี่ยวกับประสิทธิภาพที่เกี่ยวข้อง
มีค่าใช้จ่ายเพียงเล็กน้อยเท่านั้นที่เรียกวิธีการขยายสำหรับการสร้างโดยtuple
เปรียบเทียบกับการใช้KeyValuePair
โดยตรงซึ่งไม่ควรเป็นปัญหาหากคุณกำหนดKeyValuePair
คุณสมบัติของKey
และValue
ตัวแปรลูปใหม่อย่างไรก็ตาม
ในทางปฏิบัติไวยากรณ์ใหม่นี้เหมาะมากสำหรับกรณีส่วนใหญ่ยกเว้นสถานการณ์จำลองประสิทธิภาพสูงพิเศษระดับต่ำซึ่งคุณยังคงมีตัวเลือกที่จะไม่ใช้ในจุดเฉพาะนั้น
ลองดูสิ: บล็อก MSDN - คุณสมบัติใหม่ใน C # 7
kvp.Key
และkvp.Value
ใช้คีย์และค่าตามลำดับ ด้วย tuples คุณจะได้รับความยืดหยุ่นในการตั้งชื่อคีย์และค่าตามที่คุณต้องการโดยไม่ต้องใช้การประกาศตัวแปรเพิ่มเติมภายในบล็อก foreach เช่นคุณอาจตั้งชื่อคีย์ของคุณเป็นfactoryName
และค่าตามmodels
ที่เป็นประโยชน์โดยเฉพาะอย่างยิ่งเมื่อคุณได้รับลูปซ้อน (พจนานุกรมของพจนานุกรม): การบำรุงรักษาโค้ดง่ายขึ้นมาก ลองดูสิ! ;-)
ฉันรู้ว่านี่เป็นคำถามที่เก่ามาก แต่ฉันสร้างวิธีการขยายที่อาจมีประโยชน์:
public static void ForEach<T, U>(this Dictionary<T, U> d, Action<KeyValuePair<T, U>> a)
{
foreach (KeyValuePair<T, U> p in d) { a(p); }
}
public static void ForEach<T, U>(this Dictionary<T, U>.KeyCollection k, Action<T> a)
{
foreach (T t in k) { a(t); }
}
public static void ForEach<T, U>(this Dictionary<T, U>.ValueCollection v, Action<U> a)
{
foreach (U u in v) { a(u); }
}
ด้วยวิธีนี้ฉันสามารถเขียนรหัสเช่นนี้:
myDictionary.ForEach(pair => Console.Write($"key: {pair.Key}, value: {pair.Value}"));
myDictionary.Keys.ForEach(key => Console.Write(key););
myDictionary.Values.ForEach(value => Console.Write(value););
บางครั้งหากคุณต้องการระบุค่าให้ใช้การรวบรวมค่าของพจนานุกรม:
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
ฉันพบวิธีนี้ในเอกสารสำหรับคลาส DictionaryBase บน MSDN:
foreach (DictionaryEntry de in myDictionary)
{
//Do some stuff with de.Value or de.Key
}
นี่เป็นเพียงคนเดียวที่ฉันสามารถทำงานได้อย่างถูกต้องในชั้นเรียนที่สืบทอดมาจาก DictionaryBase
Hashtable
วัตถุ
ContainsKey()
ในfor
รุ่น? ซึ่งเพิ่มค่าใช้จ่ายเพิ่มเติมซึ่งไม่ปรากฏในรหัสที่คุณเปรียบเทียบ TryGetValue()
มีอยู่เพื่อแทนที่รูปแบบ "ถ้ามีคีย์รับรายการด้วยคีย์" นอกจากนี้หากdict
มีช่วงจำนวนเต็มต่อเนื่องตั้งแต่0
ถึงถึงdictCount - 1
คุณจะรู้ว่าตัวทำดัชนีไม่สามารถล้มเหลวได้ มิฉะนั้นdict.Keys
เป็นสิ่งที่คุณควรทำซ้ำ ไม่ว่าจะด้วยวิธีใดContainsKey()
/ ไม่TryGetValue()
จำเป็น สุดท้ายโปรดอย่าโพสต์ภาพหน้าจอของรหัส
ฉันจะใช้ประโยชน์จาก. NET 4.0 ขึ้นไปและให้คำตอบที่ปรับปรุงใหม่สำหรับคำตอบที่ได้รับการยอมรับเดิม:
foreach(var entry in MyDic)
{
// do something with entry.Value or entry.Key
}
วิธีมาตรฐานในการทำซ้ำในพจนานุกรมตามเอกสารอย่างเป็นทางการของ MSDN คือ:
foreach (DictionaryEntry entry in myDictionary)
{
//Read entry.Key and entry.Value here
}
ฉันเขียนส่วนขยายเพื่อวนลูปมากกว่าพจนานุกรม
public static class DictionaryExtension
{
public static void ForEach<T1, T2>(this Dictionary<T1, T2> dictionary, Action<T1, T2> action) {
foreach(KeyValuePair<T1, T2> keyValue in dictionary) {
action(keyValue.Key, keyValue.Value);
}
}
}
จากนั้นคุณสามารถโทร
myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));
ForEach
วิธีการที่คุณมีforeach (...) { }
... ดูเหมือนว่าไม่จำเป็น
ถ้าพูดว่าคุณต้องการวนซ้ำคอลเลกชันค่าโดยค่าเริ่มต้นฉันเชื่อว่าคุณสามารถใช้ IEnumerable <>, โดยที่ T คือประเภทของวัตถุค่าในพจนานุกรมและ "this" เป็นพจนานุกรม
public new IEnumerator<T> GetEnumerator()
{
return this.Values.GetEnumerator();
}
แค่ต้องการเพิ่ม 2 เซ็นต์ของฉันเพราะคำตอบส่วนใหญ่เกี่ยวข้องกับ foreach-loop โปรดดูที่รหัสต่อไปนี้:
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 กับ someList.Foreach () {} ) โดยเฉพาะเมื่อทำงานกับพจนานุกรมขนาดใหญ่และทำงานในแบบคู่ขนานไม่มี ตัวเลือก / จะไม่มีผลเลย
นอกจากนี้โปรดทราบว่าคุณจะไม่สามารถกำหนดค่าให้กับคุณสมบัติ 'ค่า' ภายใน foreach-loop ในทางกลับกันคุณจะสามารถจัดการ 'คีย์' ได้เช่นกันซึ่งอาจทำให้คุณมีปัญหาในขณะใช้งานจริง
เมื่อคุณเพียงต้องการ "อ่าน" คีย์และค่าคุณอาจใช้ IEnumerable.Select ()
var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );
foreach
ผลข้างเคียง: บังคับให้มองเห็นผลข้างเคียงที่เกิดขึ้น
var dictionary = new Dictionary<string, int>
{
{ "Key", 12 }
};
var aggregateObjectCollection = dictionary.Select(
entry => new AggregateObject(entry.Key, entry.Value));
AggregateObject
เพิ่มKeyValuePair
? "การทำซ้ำ" ตามที่ร้องขอในคำถามอยู่ที่ไหน
foreach
แต่ฉันใช้มันมาก คำตอบของฉันสมควรได้รับการลงคะแนนอย่างแท้จริงหรือไม่?
Select
ใช้การวนซ้ำเพื่อให้เกิดผลลัพธ์ แต่ไม่ใช่ตัววนซ้ำ ประเภทของสิ่งที่ย้ำ ( foreach
) ใช้สำหรับ - โดยเฉพาะอย่างยิ่งการดำเนินงานที่มีผลข้างเคียง - อยู่นอกขอบเขตของ Linq Select
รวมทั้ง แลมบ์ดาจะไม่วิ่งจนกว่าaggregateObjectCollection
จะมีการแจกแจงจริง หากคำตอบนี้ถูกใช้เป็น "เส้นทางแรก" (เช่นใช้ก่อนหน้าตรงforeach
) มันส่งเสริมการปฏิบัติที่ไม่ดี สถานการณ์อาจมีการดำเนินการ Linq ที่เป็นประโยชน์ก่อนทำซ้ำพจนานุกรม แต่ไม่ได้ตอบคำถามตามที่ถาม
พจนานุกรม <TKey, TValue>มันเป็นคลาสคอลเลกชันทั่วไปใน c # และเก็บข้อมูลในรูปแบบค่าคีย์คีย์ต้องไม่ซ้ำกันและไม่สามารถเป็น null ได้ในขณะที่ค่าสามารถซ้ำกันและเป็น null แต่ละรายการในพจนานุกรมคือ ถือว่าเป็นโครงสร้าง KeyValuePair <TKey, TValue> ซึ่งแทนค่าคีย์และค่า และด้วยเหตุนี้เราควรใช้ประเภทองค์ประกอบ KeyValuePair <TKey, TValue> ในระหว่างการวนซ้ำขององค์ประกอบ ด้านล่างเป็นตัวอย่าง
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"One");
dict.Add(2,"Two");
dict.Add(3,"Three");
foreach (KeyValuePair<int, string> item in dict)
{
Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}
ถ้าคุณต้องการใช้ลูปคุณสามารถทำได้:
var keyList=new List<string>(dictionary.Keys);
for (int i = 0; i < keyList.Count; i++)
{
var key= keyList[i];
var value = dictionary[key];
}
foreach
วนซ้ำ และประสิทธิภาพที่แย่ลงเพราะnew List<string>(dictionary.Keys)
จะวนซ้ำdictionary.Count
ก่อนที่คุณจะมีโอกาสวนซ้ำด้วยตัวคุณเอง นอกเหนือจากที่ขอให้ "วิธีที่ดีที่สุด" เป็นเรื่องส่วนตัวฉันไม่เห็นว่าสิ่งนี้จะมีคุณสมบัติเป็น "วิธีที่ดีที่สุด" หรือ "วิธีมาตรฐาน" ที่คำถามนั้นถาม ถึง "ถ้าคุณต้องการใช้สำหรับลูป ... " ฉันจะตอบโต้ด้วย " ไม่ต้องใช้for
ลูป"
foreach (var pair in dictionary.ToArray()) { }
ทุกครั้ง ถึงกระนั้นฉันคิดว่ามันเป็นการดีที่จะให้ความกระจ่างในคำตอบของสถานการณ์เฉพาะที่เราต้องการใช้รหัสนี้และความหมายของการทำเช่นนั้น
ง่ายด้วย linq
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "American Ipa");
dict.Add(2, "Weiss");
dict.ToList().ForEach(x => Console.WriteLine($"key: {x.Key} | value: {x.Value}") );
ToList()
เพราะForEach()
มีการกำหนดไว้ในList<>
ชั้นเรียนเท่านั้น แต่ทำไมถึงทำแบบนั้นทั้งหมดแทนที่จะเป็นแค่foreach (var pair in dict) { }
? ฉันจะบอกว่ามันง่ายกว่าและไม่มีนัยยะของหน่วยความจำ / ประสิทธิภาพที่เหมือนกัน คำตอบที่ถูกต้องนี้ได้เสนอไว้แล้วในคำตอบนี้จาก 3.5 ปีก่อนอย่างไรก็ตาม
นอกจากโพสต์อันดับสูงสุดที่มีการสนทนาระหว่างการใช้
foreach(KeyValuePair<string, string> entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
หรือ
foreach(var entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
สมบูรณ์ที่สุดคือต่อไปนี้เพราะคุณสามารถดูประเภทพจนานุกรมจากการเริ่มต้น kvp คือ KeyValuePair
var myDictionary = new Dictionary<string, string>(x);//fill dictionary with x
foreach(var kvp in myDictionary)//iterate over dictionary
{
// do something with kvp.Value or kvp.Key
}