GroupBy () içindeki List <string> alanı nasıl dahil edilir

Aug 19 2020

Diff nesnelerinin bir listesi var Diff buna benziyor

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 sorgum yapacağını düşündüğüm şeyi yapmıyor. Ben geçen am diff.propertiesiçinde GroupBy()bir Liste olan ve grubuna istediğinizde bir liste maçında tüm dize değerleri

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();

Arasındaki tek fark resultsve diffstekil olmasıdır DayOfWeekönceden depolanmış olan diffsşimdi çoğul konur DaysOfWeekalan (ancak listede sadece 1 öğe). Şu anda, her ikisinde de aynı öğe sayısı resultsve diffs.

Sonuçlar listesinde görmek istediğim şeyler:

  1. Tüm gruplamalara göre eşleşmeye dayalı olarak konsolide eden daha kısa bir liste (fark. Özellikler listesi değerleri dahil)
  2. Bu aynı zamanda Haftanın Günleri listesinde 1'den fazla öğe anlamına gelir.

Sorum şu:

Ne görmek istediğimi görmek için yukarıdaki LINQ sorgumu nasıl değiştirebilirim results?

Yanıtlar

4 TravisJ Aug 19 2020 at 06:02

Anonim türle kullandığınız gruplama List<string>, 1-1 gruplanmamış bir küme elde etmenize neden olan bir içerir .

İkisine de ihtiyacın var

  • gruplama ve aşırı yükleme için özel bir sınıf kullanın GetHashCodeve Equalsbu soruda gösterildiği gibi: Değer nesneleri yerine referans nesnelere göre gruplamak için LINQ GroupBy'yi kullanma

- VEYA -

  • değerlerden bir dize veya bunların bir alt kümesini oluşturarak, diff.properties, diff.Action, diff.Type, diff.startdatetime, diff.enddatetime, diff.rateId, diff.rateDescriptiongrup için benzersiz bir anahtar görevi görecek ( )
2 RufusL Aug 19 2020 at 07:16

Senin Birkaç GroupByözelliklerine referans türleri vardır ve bunların hiçbiri maç olacak böylece bu türleri için varsayılan karşılaştırıcısı, bir refernence karşılaştırmasıdır. Bunun üstesinden gelmek EqualityCompareriçin, Diffsınıf için kendimizinkini yazabiliriz, böylece onları kendi yöntemimizle karşılaştırabiliriz:

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;
    }
}

Son olarak, bu özel karşılaştırıcıyı GroupByyöntemimizde kullanabiliriz:

var results = diffs
    .GroupBy(diff => new DiffEqualityComparer())
    .Select( // rest of code omitted 
1 surprised_ferret Aug 19 2020 at 06:48

Ben çözdüm!

Başka bir soruyu okumak ve bu sorudaki yorumlar + cevaplar bunu anlamama yardımcı oldu!

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'da bu düzenlemeyi yaptım:


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();