如果值位于上一条记录中,请在 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 查询中选择 null

假设您使用 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
}));