Cara menggabungkan bidang Daftar <string> di GroupBy ()
Saya memiliki daftar objek Diff terlihat seperti ini
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
}
Kueri LINQ saya tidak melakukan apa yang menurut saya akan dilakukannya. Saya lewat di diff.properties
dalam GroupBy()
, yang merupakan Daftar dan saya ingin kelompok ketika semua nilai string dalam daftar pertandingan
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();
Satu-satunya perbedaan antara results
dan diffs
adalah bahwa bentuk tunggal DayOfWeek
yang sebelumnya disimpan diffs
sekarang dimasukkan ke dalam DaysOfWeek
bidang jamak (tetapi hanya 1 item dalam daftar). Saat ini, # item yang sama di results
dan diffs
.
Apa yang ingin saya lihat di daftar hasil adalah:
- Daftar yang lebih pendek yang menggabungkan berdasarkan pencocokan pada semua pengelompokan (termasuk nilai daftar properti berbeda)
- Ini juga berarti lebih dari 1 item dalam daftar DaysOfWeek.
Pertanyaanku adalah:
Bagaimana cara mengubah kueri LINQ saya di atas untuk melihat apa yang ingin saya lihat results
?
Jawaban
Pengelompokan yang Anda gunakan dengan tipe anonim berisi List<string>
yang menyebabkan Anda mendapatkan 1-1 set tidak dikelompokkan.
Anda juga harus melakukannya
- gunakan kelas khusus untuk pengelompokan dan kelebihan beban
GetHashCode
danEquals
seperti yang ditunjukkan dalam pertanyaan ini: Menggunakan LINQ GroupBy untuk mengelompokkan berdasarkan objek referensi, bukan objek nilai
- ATAU -
- menulis string dari nilai, atau bagiannya, dipilih (
diff.properties, diff.Action, diff.Type, diff.startdatetime, diff.enddatetime, diff.rateId, diff.rateDescription
) yang akan berfungsi sebagai kunci unik untuk mengelompokkan
Beberapa GroupBy
properti Anda adalah jenis referensi, dan pembanding default untuk jenis ini adalah perbandingan referensi, jadi tidak satu pun dari properti ini yang cocok. Untuk mengatasi hal ini, kita dapat menulis kita sendiri EqualityComparer
untuk Diff
kelas sehingga kita dapat membandingkan mereka dengan cara kita sendiri:
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;
}
}
Dan akhirnya kita bisa menggunakan pembanding khusus ini dalam GroupBy
metode kita :
var results = diffs
.GroupBy(diff => new DiffEqualityComparer())
.Select( // rest of code omitted
Saya menyelesaikannya!
Membaca pertanyaan lain dan komentar + jawaban dalam pertanyaan ini membantu saya mengetahuinya!
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;
}
}
Dan saya melakukan pengeditan ini ke 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();