วิธีการรวมฟิลด์รายการ <string> ใน GroupBy ()
ฉันมีรายการของวัตถุที่แตกต่างลักษณะต่างกันเช่นนี้
public class Diff
{
ChangeAction Action // ChangeAction is an Enum
string Type
DateTime StartDateTime
DateTime EndDateTime
int rateId
string rateDescription
List<string> properties
DayOfWeek day
List<DaysOfWeek> DaysOfWeek
DayOfWeek DayOfWeek
}
แบบสอบถาม LINQ ของฉันไม่ทำในสิ่งที่ฉันคิดว่าจะทำ ฉันกำลังผ่านในdiff.properties
ในGroupBy()
ซึ่งเป็นรายการและฉันต้องการให้กลุ่มเมื่อค่าสตริงทั้งหมดในการแข่งขันรายการ
var results = diffs
.GroupBy(diff => new { diff.properties, diff.Action, diff.Type, diff.StartDateTime,
diff.EndDateTime, diff.rateId, diff.rateDescription})
.Select(group => new Diff(
group.Key.Action,
group.Key.ScheduleType,
group.Key.StartDateTime,
group.Key.EndDateTime,
group.Key.rateId,
group.Key.rateDescription,
group.Key.properties,
group
.Select(ts => ts.DayOfWeek)
.Distinct()
.OrderBy(dow => dow)
.ToList()))
.ToList();
ความแตกต่างเพียงอย่างเดียวระหว่างresults
และdiffs
คือตอนนี้เอกพจน์DayOfWeek
ที่เก็บไว้ก่อนหน้านี้diffs
จะถูกใส่ลงในDaysOfWeek
ฟิลด์พหูพจน์(แต่มีเพียง 1 รายการในรายการ) ขณะนี้มี # รายการเดียวกันทั้งในresults
และdiffs
.
สิ่งที่ฉันต้องการเห็นในรายการผลลัพธ์คือ:
- รายการที่สั้นกว่าที่รวมตามการจับคู่บนการจัดกลุ่มทั้งหมด (รวมถึงค่ารายการ diff.properties)
- นอกจากนี้ยังหมายถึงมากกว่า 1 รายการในรายการ DaysOfWeek
คำถามของฉันคือ:
ฉันจะเปลี่ยนข้อความค้นหา LINQ ด้านบนเพื่อดูสิ่งที่ฉันต้องการดูได้results
อย่างไร
คำตอบ
การจัดกลุ่มที่คุณใช้กับประเภทที่ไม่ระบุตัวตนมีสิ่งList<string>
ที่ทำให้คุณได้รับชุดที่ไม่ได้จัดกลุ่ม 1-1
คุณต้องทำอย่างใดอย่างหนึ่ง
- ใช้คลาสที่กำหนดเองสำหรับการจัดกลุ่มและการโอเวอร์โหลด
GetHashCode
และEquals
ดังที่แสดงในคำถามนี้: การใช้ LINQ GroupBy เพื่อจัดกลุ่มตามวัตถุอ้างอิงแทนที่จะเป็นวัตถุค่า
- หรือ -
- เขียนสตริงจากค่าหรือส่วนย่อยของพวกเขาถูกเลือก (
diff.properties, diff.Action, diff.Type, diff.startdatetime, diff.enddatetime, diff.rateId, diff.rateDescription
) ซึ่งจะทำหน้าที่เป็นคีย์เฉพาะในการจัดกลุ่มด้วย
พGroupBy
ร็อพเพอร์ตี้บางส่วนของคุณเป็นประเภทอ้างอิงและตัวเปรียบเทียบเริ่มต้นสำหรับประเภทเหล่านี้เป็นการเปรียบเทียบอ้างอิงดังนั้นจึงไม่มีสิ่งใดที่จะตรงกัน เพื่อเอาชนะสิ่งนี้เราสามารถเขียนของเราเองEqualityComparer
สำหรับDiff
ชั้นเรียนเพื่อให้เราสามารถเปรียบเทียบได้ในแบบของเรา:
public class DiffEqualityComparer : IEqualityComparer<Diff>
{
public bool Equals(Diff first, Diff second)
{
if (first == null || second == null) return ReferenceEquals(first, second);
if (first.Properties == null && second.Properties != null) return false;
if (first.Properties != null && second.Properties == null) return false;
if (first.Properties != null && second.Properties != null &&
!first.Properties.OrderBy(p => p)
.SequenceEqual(second.Properties.OrderBy(p => p)))
return false;
if (!first.Action.Equals(second.Action)) return false;
if (!string.Equals(first.Type, second.Type)) return false;
if (!first.Start.Equals(second.Start)) return false;
if (!first.End.Equals(second.End)) return false;
if (!first.RateId.Equals(second.RateId)) return false;
if (!string.Equals(first.RateDescription, second.RateDescription)) return false;
return true;
}
public int GetHashCode(Diff obj)
{
var hash = obj.Properties?.Aggregate(0,
(accumulator, current) => accumulator * 17 + current.GetHashCode()) ?? 0;
hash = hash * 17 + obj.Action.GetHashCode();
hash = hash * 17 + obj.Type?.GetHashCode() ?? 0;
hash = hash * 17 + obj.Start.GetHashCode();
hash = hash * 17 + obj.End.GetHashCode();
hash = hash * 17 + obj.RateId.GetHashCode();
hash = hash * 17 + obj.RateDescription?.GetHashCode() ?? 0;
return hash;
}
}
และในที่สุดเราก็สามารถใช้ตัวเปรียบเทียบที่กำหนดเองนี้ในGroupBy
วิธีของเรา:
var results = diffs
.GroupBy(diff => new DiffEqualityComparer())
.Select( // rest of code omitted
ฉันแก้ไขแล้ว!
การอ่านคำถามอื่นและความคิดเห็น + คำตอบในคำถามนี้ช่วยให้ฉันเข้าใจได้!
public class DiffComparer : IEqualityComparer<Diff>
{
public bool Equals(Diff x, Diff y)
{
return x.Action == y.Action &&
x.Type == y.Type &&
x.StartDateTime == y.StartDateTime &&
x.EndDateTime == y.EndDateTime &&
x.rateId== y.rateId &&
x.rateDescription == y.rateDescription &&
x.properties.SequenceEqual(y.properties);
}
public int GetHashCode(Diff x)
{
int hash = 17;
hash = hash * 23 + x.Action.GetHashCode();
hash = hash * 23 + x.Type.GetHashCode();
hash = hash * 23 + x.StartDateTime .GetHashCode();
hash = hash * 23 + x.EndDateTime.GetHashCode();
hash = hash * 23 + x.rateId.GetHashCode();
hash = hash * 23 + x.rateDescription.GetHashCode();
foreach (string prop in x.properties)
{
hash = hash * 31 + prop.GetHashCode();
}
return hash;
}
}
และฉันได้ทำการแก้ไขนี้กับ LINQ:
var results = diffs
.GroupBy(diff => diff, new DiffComparer())
.Select(group => new Diff(
group.Key.Action,
group.Key.ScheduleType,
group.Key.StartDateTime,
group.Key.EndDateTime,
group.Key.rateId,
group.Key.rateDescription,
group.Key.properties,
group
.Select(ts => ts.DayOfWeek)
.Distinct()
.OrderBy(dow => dow)
.ToList()))
.ToList();