如果值在先前记录中,则在linq查询中选择null

时间:2013-10-01 04:59:08

标签: c# linq

考虑以下问题:

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.Name,我想在t1的结果的其余部分使用null或空字符串

我已经知道我可以遍历结果,但是我将它用作数据源,并希望做一些基于设置的事情。

有没有办法在单个查询中完成此操作?

5 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

我认为你需要在这里进行交叉连接。 试试这个。

//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();

答案 2 :(得分:1)

您可以使用以下内容,它基本上模拟了您尝试使用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
    }}));

答案 3 :(得分:1)

与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, }));

答案 4 :(得分:1)

要以不同方式处理序列中的第一项,您可以使用传入索引的Select重载,我们可以将其与零进行比较。

在查询语法中无法访问该重载,并且查询看起来使用所有方法语法而不是混合和匹配更好。

var query = list1.SelectMany(t1 => list2.Select((t2, i) => new
{
    Name1 = i == 0 ? t1.Name : null,
    Name2 = t2.Name
}));