1

考虑以下查询:

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 或空字符串

我已经知道我可以遍历结果,但我将其用作数据源并想做一些基于集合的事情。

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

4

5 回答 5

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();
于 2013-10-01T05:28:49.920 回答
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();
于 2013-10-01T05:09:59.350 回答
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
    }}));
于 2013-10-01T05:41:59.803 回答
1

与 pswg 想出的相距不远,这不使用查询语法。它避免.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, }));
于 2013-10-01T06:48:15.573 回答
1

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

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

var query = list1.SelectMany(t1 => list2.Select((t2, i) => new
{
    Name1 = i == 0 ? t1.Name : null,
    Name2 = t2.Name
}));
于 2013-10-02T17:08:59.607 回答