我在Linq有3套,像这样:
struct Index
{
string code;
int indexValue;
}
List<Index> reviews
List<Index> products
List<Index> pages
这些列表有不同的代码。
我想将这些集合合并如下:
我如何在Linq中执行此操作?
编辑:等等,如果没有.NET 4.0,是否有更改?
非常感谢
答案 0 :(得分:4)
您可以使用Zip
进行出价。
var trios = reviews
.Zip(products, (r, p) => new { Review = r, Product = p })
.Zip(pages, (rp, p) => new { rp.Review, rp.Product, Page = p });
修改强>
对于.NET 3.5,可以非常轻松地实现Zip
:但是有一些 gotcha 。 Jon Skeet有一篇关于如何实现LINQ到对象运算符(用于教育目的)的精彩系列文章,包括this post, on Zip
。整个系列的源代码edulinq可以是found on Google Code。
答案 1 :(得分:1)
简单的答案
要将它们合并到一个没有任何常见数据的公共列表中,使用它们显示的顺序,您可以use the Zip
method:
var rows = reviews
.Zip(products, (r, p) => new { Review = r, Product = p })
.Zip(pages, (rp, page) => new { rp.Review, rp.Product, Page = page });
此解决方案的问题在于列表的长度必须相同,否则您的结果将被切割为原始列表的最短列表。
编辑:
如果您无法使用.Net 4,请查看Jon Skeet's blog posts on a clean-room implementation of Linq和His article on Zip in particular。
如果您使用的是.Net 2,请尝试使用他的库(可能)或try LinqBridge
如何处理不同长度的列表
您可以将列表预填充到所需的长度。我找不到现有方法来执行此操作,因此我将使用扩展方法:
public static class EnumerableExtensions
{
public static IEnumerable<T> Pad<T>(this IEnumerable<T> source,
int desiredCount, T padWith = default(T))
{
// Note: Not using source.Count() to avoid double-enumeration
int counter = 0;
var enumerator = source.GetEnumerator();
while(counter < desiredCount)
{
yield return enumerator.MoveNext()
? enumerator.Current
: padWith;
++counter;
}
}
}
你可以像这样使用它:
var paddedReviews = reviews.Pad(desiredLength);
var paddedProducts = products.Pad(desiredLength,
new Product { Value2 = DateTime.Now }
);
完整编译样本和相应的输出
using System;
using System.Collections.Generic;
using System.Linq;
class Review
{
public string Value1;
}
class Product
{
public DateTime Value2;
}
class Page
{
public int Value3;
}
public static class EnumerableExtensions
{
public static IEnumerable<T> Pad<T>(this IEnumerable<T> source,
int desiredCount, T padWith = default(T))
{
int counter = 0;
var enumerator = source.GetEnumerator();
while(counter < desiredCount)
{
yield return enumerator.MoveNext()
? enumerator.Current
: padWith;
++counter;
}
}
}
class Program
{
static void Main(string[] args)
{
var reviews = new List<Review>
{
new Review { Value1 = "123" },
new Review { Value1 = "456" },
new Review { Value1 = "789" },
};
var products = new List<Product>()
{
new Product { Value2 = DateTime.Now },
new Product { Value2 = DateTime.Now.Subtract(TimeSpan.FromSeconds(5)) },
};
var pages = new List<Page>()
{
new Page { Value3 = 123 },
};
int maxCount = Math.Max(Math.Max(reviews.Count, products.Count), pages.Count);
var rows = reviews.Pad(maxCount)
.Zip(products.Pad(maxCount), (r, p) => new { Review = r, Product = p })
.Zip(pages.Pad(maxCount), (rp, page) => new { rp.Review, rp.Product, Page = page });
foreach (var row in rows)
{
Console.WriteLine("{0} - {1} - {2}"
, row.Review != null ? row.Review.Value1 : "(null)"
, row.Product != null ? row.Product.Value2.ToString() : "(null)"
, row.Page != null ? row.Page.Value3.ToString() : "(null)"
);
}
}
}
123 - 9/7/2011 10:02:22 PM - 123
456 - 9/7/2011 10:02:17 PM - (null)
789 - (null) - (null)
使用Join
代码
此操作不是逻辑Join
。这是因为您匹配索引,而不是每个对象的任何数据。每个对象都必须有一个共同的其他数据(除了它们在列表中的位置),你可以在关系数据库中找到Join
的意义。