假设,例如,在我的 C# 代码中,我有 MyClass
,定义为:
public class MyClass
{
public string GroupName;
public DateTime Dt;
public int Id;
public string Val;
.... other properties ....
}
假设我有以下 List<MyClass>
(将其显示为表格,因为它似乎是描述内容的最简单方法):
GroupName: Dt: Id: Val:
Group1 2016/01/01 1 Val1
Group1 2016/01/02 1 Val1
Group1 2016/01/03 1 Val1
Group1 2016/01/04 1 Val2
Group1 2016/01/05 1 Val3
Group1 2016/01/06 1 Val1
Group1 2016/01/07 1 Val1
Group1 2016/01/08 1 Val4
Group1 2016/01/09 1 Val4
显然,对于多个 GroupName
会发生同样的事情s和不同Id
我想从此列表中得到的是,对于任何命名组,每个第一个更改的值 - 因此 Group1
的输出会是:
Dt: Id: Val:
2016/01/01 1 Val1
2016/01/04 1 Val2
2016/01/05 1 Val3
2016/01/06 1 Val1
2016/01/08 1 Val4
换句话说,对于给定的 GroupName
:
- 按编号分组
- 按日期订购
- 选择每个组中的任何项目,其中 item[index] != item[index-1]
所以,我得到了以下代码:
public IEnumerable<MyClass> GetUpdatedVals(List<MyClass> myVals, string groupName)
{
var filteredVals = myVals.Where(v => v.GroupName == groupName).ToList();
return filteredVals
.OrderBy(v => v.Id)
.ThenBy(v => v.Dt)
.Where((v, idx) => idx == 0 || v.Id != filteredVals[idx - 1].Id || v.Val != filteredVals[idx - 1].Val)
.Select(v => v);
}
但似乎应该有更好的方法通过 Linq 使用 GroupBy 或无需创建单独的持有列表的方法来执行此操作。
有什么想法吗?或者这是“非常好”/最好的方法?
谢谢!
最佳答案
如果你想要更优雅的东西,你可以使用 https://stackoverflow.com/a/4682163/6137718 中描述的 GroupAdjacent by 函数:
public static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> GroupAdjacentBy<T>(
this IEnumerable<T> source, Func<T, T, bool> predicate)
{
using (var e = source.GetEnumerator())
{
if (e.MoveNext())
{
var list = new List<T> { e.Current };
var pred = e.Current;
while (e.MoveNext())
{
if (predicate(pred, e.Current))
{
list.Add(e.Current);
}
else
{
yield return list;
list = new List<T> { e.Current };
}
pred = e.Current;
}
yield return list;
}
}
}
}
在按 Id 和 Dt 排序后,我们可以使用它对具有相同 Val 的所有相邻元素进行分组。然后从每个组中,我们选择第一个,因为它代表最近的变化。更新后的代码看起来像这样:
public IEnumerable<MyClass> GetUpdatedVals(List<MyClass> myVals, string groupName)
{
return myVals
.Where(v => v.GroupName == groupName)
.OrderBy(v => v.Id)
.ThenBy(v => v.Dt)
.GroupAdjacentBy((x, y) => x.Val == y.Val && x.Id == y.Id)
.Select(g => g.First());
}
关于c# - Linq - 分组然后比较每个组内的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36455168/