让我们说我有这个表/ IQueriable
+------+------+------+------------+-------------+
| col1 | col2 | col3 | grouperCol | selectorCol |
+------+------+------+------------+-------------+
| 1 | John | Doe | mail1 | |
| 1 | John | Doe | mail2 | 1 |
| 1 | John | Doe | mail3_x | |
| 2 | Bob | Ross | mail1 | 1 |
| 2 | Bob | Ross | mail2_x | |
| 2 | Bob | Ross | mail3_x | |
| 3 | Jane | Doe | mail1 | |
| 3 | Jane | Doe | mail2 | |
| 3 | Jane | Doe | mail3 | |
+------+------+------+------------+-------------+
我想得到这个结果:
+------+------+------+------------+-------------+
| col1 | col2 | col3 | grouperCol | selectorCol |
+------+------+------+------------+-------------+
| 1 | John | Doe | mail2 | 1 |
| 2 | Bob | Ross | mail1 | 1 |
| 3 | Jane | Doe | mail1 | |
+------+------+------+------------+-------------+
基本上,我需要保留一行,选择selectorCol不为null或第一行不为空的行。
如何在c#中执行此操作?
我可能需要做类似
的操作var filtered = context.table.GroupBy(x => x.col1).Where(...
但是我已经很想写短片了。
我可以用foreach或其他内容创建一个新列表,但我想可以用1行完成?
谢谢!
答案 0 :(得分:0)
如果您只想基于col1
进行操作,则:
var result = context.table.GroupBy(x => x.col1)
.Select(g => g.FirstOrDefault(x =>selectorCol != null)??g.First());
名字和姓氏(col1
,col2
);
var result = context.table.GroupBy(x => {x.col1, x.col2})
.Select(g => g.FirstOrDefault(x =>selectorCol != null)??g.First());
答案 1 :(得分:0)
这是您的一线客:
.GroupBy(x => x.col1, (k, g) => g.FirstOrDefault(x => x.selectorCol == 1) ?? g.FirstOrDefault())
但是,我很好奇这将生成什么样的数据库查询。分组减少可能会在内存中完成。
编辑:显然,上面的linq生成带有子查询的查询。最好将其分为两种方法以避免性能问题:
.OrderBy(x => x.selectorCol == null)
.GroupBy(x => x.col1, (k, g) => g.FirstOrDefault())
答案 2 :(得分:0)
基本上,我需要保留一行,选择selectorCol不为null或第一行不为空的行。
您没有明确地说过,但我假设如果两个行具有相同的Col1
,则它们也具有相同的Col2
和Col3
需求给定一个MyRows
序列,创建一个结果序列,该序列是从MyRows
组创建的,其值与Col1
相同。从每个组中,我希望第一个元素具有非空值SelectorCol
如果精确地编写需求,这似乎并不困难。唯一的问题是:组的第一个元素是什么?那是索引最低的那个吗?
由于GroupBy无法保证保持原始顺序,因此我们必须记住原始项目的索引。
Col1
的具有相同值的项目分组。
// first remember the original index
var result = myRows.Select( (row, index) => new
{
Index = index
Row = row,
}
// Then make groups of rows with same value for Col1
.GroupBy(selectResult => selectResult.Row.Col1,
// Parameter resultSelector: get the key of each group (= common Col1 value)
// and all rows that have this Col1 value
// keep only the groupElements that have a non-null value for SelectorCol
(col1, rowsWithThisCol1) => rows.WithThisCol1
.Where(groupElement => groupElement.Row.SelectorCol != null)
// from the remaining rows, keep the one with the lowest index
.OrderBy(groupElement => groupElement.Index)
// we don't need the Index anymore, select only the Row
.Select(groupElement => groupElement.Row)
// and keep the first:
.FirstOrDefault();
尽管此方法可行,但如果只希望索引值最低的元素来排序所有组元素,则有点浪费。如果只想枚举一次,请使用“聚合”。因此,而不是OrderBy:
.Aggregate((groupElementWithLowestIndex, groupElement) =>
// if the index of groupElement is lower,
// then that element becomes the one with the lowest index
(groupElement.Index < groupElementWithLowestIndex.Index) ?
groupElement : groupElementWithLowestIndex)
// result: the one and only groupElement with the lowest index
// note: you are certain that no group is empty! So there is always one with lowest index
// get rid of the index, keep only the Row
.Row;