Как включить поле List <string> в GroupBy ()
У меня есть список объектов Diff. Diff выглядит так
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();