如果值位于上一条记录中,请在 linq 查询中选择 null
本文关键字:请在 linq 查询 null 选择 记录 一条 如果 | 更新日期: 2023-09-27 18:33:20
请考虑以下查询:
var ds = (from t1 in list1
from t2 in list2
select new {t1.Name, t2.Name}
).ToList();
这将返回类似以下内容:(粗略表示)
Name1, InnerName1
Name1, InnerName2
Name2, InnerName1
Name2, InnerName2
我想要得到的是:
Name1, InnerName1
Null, InnerName2
Name2, InnerName1
Null, InnerName2.
意思是,如果我已经有 t1。列表中的名称,我希望在 t1 的其余结果上为空或空字符串。
我已经知道我可以循环浏览结果,但我将其用作数据源,并希望做一些基于集的事情。
有没有办法在单个查询中完成此操作?
假设您使用 Linq-to-Objects,您可以执行以下操作:
string previous = null;
var results =
(from t1 in list1
from t2 in list2
select new {
Name1 = (previous == t1.Name) ? null : (previous = t1.Name),
Name2 = t2.Name
})
.ToList();
但这依赖于副作用,并不是特别优雅。您可能更喜欢这样的东西:
var result =
(from t1 in list1
select
list2.Take(1)
.Select(t2 => new { Name1 = t1.Name, Name2 = t2.Name })
.Concat(list2.Skip(1)
.Select(t2 => new { Name1 = (string)null, Name2 = t2.Name }))
.SelectMany(x => x)
.ToList();
您可以使用
以下内容,它基本上模拟了您试图通过使用Aggregate
避免的循环。不幸的是,它不能再使用匿名类,因为我们需要使用Enumerable.Empty<Data>()
来启动聚合:
class Data { public string Name; public string Inner; };
// Test data
var data = new Data[]
{
new Data {Name = "Name1", Inner = "InnerName1"},
new Data {Name = "Name1", Inner = "InnerName2"},
new Data {Name = "Name2", Inner = "InnerName1"},
new Data {Name = "Name2", Inner = "InnerName2"}
};
// remove duplicate Names
var filtered = data.Aggregate(
Enumerable.Empty<Data>(),
(list, newitem) => list.Concat(new Data[] {new Data {
Name = (list.Any() && list.Last().Name == newitem.Name)
? null : newitem.Name,
Inner = newitem.Inner
}}));
我认为您需要在此处进行交叉连接。试试这个。
//will get null values for both
var ds = (from t1 in list1
join t2 in list2 into t3
from objt3 in t3.DefaultIfEmpty()
select new {t1.Name, objt3.Name}
).ToList();
编辑:
//will get null values for second list
var ds = (from t1 in list1
join t2 in list2 into t3
from objt3 in t3.DefaultIfEmpty()
where t1 != null
select new {t1.Name, objt3.Name}
).ToList();
更新:
//will get null values for second list
var ds = (from t1 in list1
where t1 != null
join t2 in list2 into t3
from objt3 in t3.DefaultIfEmpty()
select new {t1.Name, objt3.Name}
).ToList();
与 p.s.w.g. 想出的不远,这不使用查询语法。它避免.First()
并使用Zip
。
var listResult = list1.SelectMany(x => (new[] { x, })
.Concat(Enumerable.Repeat((string)null, int.MaxValue))
.Zip(list2, (y, z) => new { Name1 = y, Name2 = z, }));
要以不同的方式处理序列中的第一项,您只需使用传入索引的Select
的重载,我们可以将其与零进行比较。
该重载在查询语法中无法访问,并且查询看起来更好,使用所有方法语法而不是混合和匹配。
var query = list1.SelectMany(t1 => list2.Select((t2, i) => new
{
Name1 = i == 0 ? t1.Name : null,
Name2 = t2.Name
}));