ilookup vs. igruping
سؤال
لقد كنت تواجه مشكلة في توضيح الاختلافات بين ILookup<TKey, TVal>
و IGrouping<TKey, TVal>
, ، وأنا فضولي إذا فهمت ذلك بشكل صحيح الآن. مركبة Linq المشكلة عن طريق إنتاج تسلسل IGrouping
البنود بينما تعطيني أيضا ToLookup
طريقة التمديد. لذلك شعرت وكأنها كانت هي نفسها حتى نظرت عن كثب.
var q1 =
from n in N
group n by n.MyKey into g
select g;
// q1 is IEnumerable<IGrouping<TKey, TVal>>
وهو ما يعادل:
var q2 = N.GroupBy(n => n.MyKey, n => n);
// q2 is IEnumerable<IGrouping<TKey, TVal>>
الذي يبدو كثيرا مثل:
var q3 = N.ToLookup(n => n.MyKey, n => n);
// q3 is ILookup<TKey, TVal>
هل أنا صحيح في التظليل التالي؟
- أ
IGrouping<TKey, TVal>
هي مجموعة واحدة (أي تسلسل مفاعل)، مماثلة لKeyValuePair<TKey, TVal>
حيث القيمة هي في الواقع سلسلة من العناصر (بدلا من عنصر واحد) - أ
IEnumerable<IGrouping<TKey, TVal>>
هو سلسلة من هؤلاء (مماثلة لما تحصل عليه عند التكرارIDictionary<TKey, TVal>
- أ
ILookup<TKey, TVal>
هو أشبهIDictionary<TKey, TVal>
حيث القيمة هي في الواقع سلسلة من العناصر
المحلول
نعم، كل هذه صحيحة.
و ILookup<TKey, TValue>
يمتد أيضا IEnumerable<IGrouping<TKey, TValue>>
حتى تتمكن من تكرار جميع أزواج المفتاح / المجموعة وكذلك (أو بدلا من) مجرد البحث عن مفاتيح معينة.
أعتقد أساسا ILookup<TKey,TValue>
كما هو مثل IDictionary<TKey, IEnumerable<TValue>>
.
نضع في اعتبارنا أن ToLookup
هي عملية "هل الآن" (الإعدام الفوري) في حين أ GroupBy
مؤجلة. كما يحدث، مع الطريقة التي "سحب LinQ" يعمل، عندما تبدأ السحب IGrouping
S من نتيجة GroupBy
, ، يجب أن تقرأ جميع البيانات على أي حال (نظرا لأنك لا تستطيع تبديل Group Midway)، في حين أنه في تطبيقات أخرى قد تكون قادرة على إنتاج نتيجة تدفق. (يفعل في دفع LINQ؛ أتوقع أن يكون LinQ للأحداث هو نفسه.)
نصائح أخرى
هناك فرق آخر مهم بين ILOOKUP و IDITIONARY: إن السابق يفرض الاستخدام غير المتحقاق بمعنى أن فيما يلي أي طرق لتغيير البيانات (باستثناء عندما يقوم المستهلك بإلقاء صريح). على النقيض من ذلك، فإن التصدي له أساليب مثل "إضافة" والتي تسمح بتغيير البيانات. لذلك، من وجهة نظر البرمجة الوظيفية و / أو البرمجة الموازية، ILOOKUP هو أجمل. (أتمنى فقط أن هناك أيضا إصدار من ILOOKUP يعين قيمة واحدة فقط إلى مفتاح بدلا من مجموعة.)
(راجع للشغل.، يبدو أن الأمر يستحق الإشارة إلى أن العلاقة بين iEnumerable و iilist هي مشابهة إلى حد ما بين ILOOKUP و IDECTIONARY - السابق غير قابل للتغيير، وهذا الأخير ليس كذلك.
GroupBy
و ToLookUp
لديه نفس الوظيفة تقريبا إلا هذه: المرجعي
GroupBy: يقوم مشغل GroupBy بإرجاع مجموعات من العناصر بناء على بعض القيمة الرئيسية. تمثل كل مجموعة بواسطة كائن Igrouping.
TOLOKUP: TOLOOKUP هو نفسه Gobby؛ الفرق الوحيد هو تنفيذ GroupBy مؤجل في حين أن تنفيذ TolookUp فوري.
يتيح مسح الفرق باستخدام نموذج التعليمات البرمجية. لنفترض أن لدينا فئة تمثل Person
نموذج:
class Personnel
{
public int Id { get; set; }
public string FullName { get; set; }
public int Level { get; set; }
}
بعد ذلك نحدد قائمة personnels
على النحو التالي:
var personnels = new List<Personnel>
{
new Personnel { Id = 1, FullName = "P1", Level = 1 },
new Personnel { Id = 2, FullName = "P2", Level = 2 },
new Personnel { Id = 3, FullName = "P3", Level = 1 },
new Personnel { Id = 4, FullName = "P4", Level = 1 },
new Personnel { Id = 5, FullName = "P5", Level =2 },
new Personnel { Id = 6, FullName = "P6", Level = 2 },
new Personnel { Id = 7, FullName = "P7", Level = 2 }
};
الآن أحتاج للحصول على personnels
مجمعة من مستواه. لدي اتجاهين هنا. استخدام GroupBy
أو ToLookUp
. وبعد إذا كنت تستخدم GroupBy
, ، كما هو مذكور من قبل، سيستخدم التنفيذ المؤجل، وهذا يعني أنه عند التكرار من خلال المجموعة قد يتم حساب العنصر التالي أو قد لا يتم حسابه حتى يطلق عليه.
var groups = personnels.GroupBy(p => p.Level);
personnels.RemoveAll(p => p.Level == 1);
foreach (var product in groups)
{
Console.WriteLine(product.Key);
foreach (var item in product)
Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
}
في الكود أعلاه، جمعت أولا personnels
, ، ولكن قبل تكرارها، أزلت بعض personnels
. وبعد مثل GroupBy
يستخدم التنفيذ المؤجل، لذلك لن تتضمن النتيجة النهائية العناصر التي تمت إزالتها، لأن التجميع ستكون الحوسبة في foreach
نقطة هنا.
انتاج:
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2
ولكن إذا قمت بإعادة كتابة التعليمات البرمجية أعلاه على النحو التالي: (لاحظ هذا الرمز هو نفس الكود السابق باستثناء GroupBy
لقد بدل بواسطة ToLookUp
)
var groups = personnels.ToLookup(p => p.Level);
personnels.RemoveAll(p => p.Level == 1);
foreach (var product in groups)
{
Console.WriteLine(product.Key);
foreach (var item in product)
Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
}
مثل ToLookUp
يستخدم التنفيذ الفوري، وهذا يعني أنه عندما أسمي ToLookUp
الطريقة، يتم إنشاء النتيجة وتطبيق المجموعة، لذلك إذا قمت بإزالة أي عنصر من personnels
قبل التكرار، لن يؤثر ذلك على النتيجة النهائية.
انتاج:
1
1 >>> P1 >>> 1
3 >>> P3 >>> 1
4 >>> P4 >>> 1
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2
ملحوظة: GroupBy
و ToLookUp
كلا عودة أنواع مختلفة أيضا.
قد تستخدم التبديل بدلا من Tolookup، لكنك بحاجة إلى الانتباه إلى هذا :(المرجعي)
إن استخدام Tolookup () يشبه إلى حد كبير ما من التبديل ()، كلاهما يسمح لك بتحديد المحددات الرئيسية ومحددات القيمة والمقارنة. الفرق الرئيسي هو أن Tolookup () يسمح (ويتوقع) المفاتيح المكررة في حين أن التبديل () لا