C# 使用LINQ将多个列表合并为一个列表

C# 使用LINQ将多个列表合并为一个列表,c#,linq,design-patterns,C#,Linq,Design Patterns,有没有一种巧妙的方法可以使用LINQ将多个列表合并成一个列表来有效地复制它 public class RGB { public int Red { get; set; } public int Green { get; set; } public int Blue { get; set; } public RGB(int red, int green, int blue) { Red = red; Green = green; Blue = blue; } }

有没有一种巧妙的方法可以使用LINQ将多个列表合并成一个列表来有效地复制它

public class RGB
{
    public int Red { get; set; }
    public int Green { get; set; }
    public int Blue { get; set; }
    public RGB(int red, int green, int blue) { Red = red; Green = green; Blue = blue; }
}

public void myFunction()
{
    List<int> red = new List<int> { 0x00, 0x03, 0x06, 0x08, 0x09 };
    List<int> green = new List<int> { 0x00, 0x05, 0x06, 0x07, 0x0a };
    List<int> blue = new List<int> { 0x00, 0x02, 0x03, 0x05, 0x09 };

    List<RGB> colors = new List<RGB>();

    colors.Add(new RGB(red[0], green[0], blue[0]));
    colors.Add(new RGB(red[1], green[1], blue[1]));
    colors.Add(new RGB(red[2], green[2], blue[2]));
    colors.Add(new RGB(red[3], green[3], blue[3]));
    colors.Add(new RGB(red[4], green[4], blue[4]));
}
公共类RGB
{
公共整数Red{get;set;}
公共整数绿色{get;set;}
公共整数蓝色{get;set;}
公共RGB(整数红色、整数绿色、整数蓝色){红色=红色;绿色=绿色;蓝色=蓝色;}
}
公共函数()
{
列表红色=新列表{0x00,0x03,0x06,0x08,0x09};
绿色列表=新列表{0x00,0x05,0x06,0x07,0x0a};
列表蓝色=新列表{0x00,0x02,0x03,0x05,0x09};
列表颜色=新列表();
添加(新的RGB(红色[0],绿色[0],蓝色[0]);
添加(新的RGB(红色[1],绿色[1],蓝色[1]);
添加(新的RGB(红色[2],绿色[2],蓝色[2]);
添加(新的RGB(红色[3],绿色[3],蓝色[3]);
添加(新的RGB(红色[4],绿色[4],蓝色[4]);
}
或者,由于列表是单独到达的,所以按如下顺序合并它们更有效

public class RGB
{
    public int Red { get; set; }
    public int Green { get; set; }
    public int Blue { get; set; }

    public RGB(int red, int green, int blue) { Red = red; Green = green; Blue = blue; }
}

public void myFunction()
{
    List<int> red = new List<int> { 0x00, 0x03, 0x06, 0x08, 0x09 };

    List<RGB> colors = new List<RGB>();

    colors.Add(new RGB(red[0], 0, 0));
    colors.Add(new RGB(red[1], 0, 0));
    colors.Add(new RGB(red[2], 0, 0));
    colors.Add(new RGB(red[3], 0, 0));
    colors.Add(new RGB(red[4], 0, 0));

    List<int> green = new List<int> { 0x00, 0x05, 0x06, 0x07, 0x0a };

    colors[0].Green = green[0];
    colors[1].Green = green[1];
    colors[2].Green = green[2];
    colors[3].Green = green[3];
    colors[4].Green = green[4];

    List<int> blue = new List<int> { 0x00, 0x02, 0x03, 0x05, 0x09 };

    colors[0].Blue = blue[0];
    colors[1].Blue = blue[1];
    colors[2].Blue = blue[2];
    colors[3].Blue = blue[3];
    colors[4].Blue = blue[4];
}
公共类RGB
{
公共整数Red{get;set;}
公共整数绿色{get;set;}
公共整数蓝色{get;set;}
公共RGB(整数红色、整数绿色、整数蓝色){红色=红色;绿色=绿色;蓝色=蓝色;}
}
公共函数()
{
列表红色=新列表{0x00,0x03,0x06,0x08,0x09};
列表颜色=新列表();
添加(新的RGB(红色[0],0,0));
添加(新的RGB(红色[1],0,0));
添加(新的RGB(红色[2],0,0));
添加(新的RGB(红色[3],0,0));
添加(新的RGB(红色[4],0,0));
绿色列表=新列表{0x00,0x05,0x06,0x07,0x0a};
颜色[0]。绿色=绿色[0];
颜色[1]。绿色=绿色[1];
颜色[2]。绿色=绿色[2];
颜色[3]。绿色=绿色[3];
颜色[4]。绿色=绿色[4];
列表蓝色=新列表{0x00,0x02,0x03,0x05,0x09};
颜色[0]。蓝色=蓝色[0];
颜色[1]。蓝色=蓝色[1];
颜色[2]。蓝色=蓝色[2];
颜色[3]。蓝色=蓝色[3];
颜色[4]。蓝色=蓝色[4];
}

是-您可以这样做:

List<int> red = new List<int> { 0x00, 0x03, 0x06, 0x08, 0x09 };
List<int> green = new List<int> { 0x00, 0x05, 0x06, 0x07, 0x0a };
List<int> blue = new List<int> { 0x00, 0x02, 0x03, 0x05, 0x09 };

List<RGB> colors = Enumerable
    .Range(0, red.Count)
    .Select(i => new RGB(red[i], green[i], blue[i]))
    .ToList();
List_A.Select(a => a.List_B).SelectMany(s => s).ToList();
List red=新列表{0x00、0x03、0x06、0x08、0x09};
绿色列表=新列表{0x00,0x05,0x06,0x07,0x0a};
列表蓝色=新列表{0x00,0x02,0x03,0x05,0x09};
列表颜色=可枚举
.范围(0,红色.计数)
.选择(i=>新RGB(红色[i],绿色[i],蓝色[i]))
.ToList();

您实际上是在尝试压缩三个集合。如果只有LINQ
Zip()
方法支持同时压缩两个以上的文件。但遗憾的是,它一次只能支持两个。但我们可以做到:

var reds = new List<int> { 0x00, 0x03, 0x06, 0x08, 0x09 };
var greens = new List<int> { 0x00, 0x05, 0x06, 0x07, 0x0a };
var blues = new List<int> { 0x00, 0x02, 0x03, 0x05, 0x09 };

var colors =
    reds.Zip(greens.Zip(blues, Tuple.Create),
        (red, tuple) => new RGB(red, tuple.Item1, tuple.Item2)
    )
    .ToList();

您可以使用Aggregate with Zip一次性压缩任意数量的IEnumerable

以下是您可以通过示例实现的方法:

var colorLists = new List<int>[] { red, green, blue };
var rgbCount = red.Count;
var emptyTriples =
    Enumerable.Repeat<Func<List<int>>>(() => new List<int>(), rgbCount)
    .Select(makeList => makeList());

var rgbTriples = colorLists.Aggregate(
    emptyTriples,
    (partialTriples, channelValues) =>
        partialTriples.Zip(
            channelValues,
            (partialTriple, channelValue) =>
            {
                partialTriple.Add(channelValue);
                return partialTriple;
            }));

var rgbObjects = rgbTriples.Select(
    triple => new RGB(triple[0], triple[1], triple[2]));
var colorLists=新列表[]{red,green,blue};
var rgbCount=红色。计数;
var空字符=
可枚举。重复(()=>new List(),rgbCount)
.Select(makeList=>makeList());
var rgbTriples=colorLists.Aggregate(
空白的文字,
(partialTriples、ChannelValue)=>
部分三角帆,拉链(
渠道价值观,
(partialTriple,channelValue)=>
{
partialTriple.Add(通道值);
返回partialTriple;
}));
var rgbObjects=rgbTriples。选择(
triple=>新RGB(triple[0],triple[1],triple[2]);

通常,使用Zip作为基础组合器可以避免输入长度变化的问题。

就其价值而言,我喜欢LINQ并经常使用它,但有时老式的方法是最好的。请注意以下示例:

        const int Max = 100000;
        var rnd = new Random();
        var list1 = Enumerable.Range(1, Max).Select(r => rnd.Next(Max)).ToList();
        var list2 = Enumerable.Range(1, Max).Select(r => rnd.Next(Max)).ToList();

        DateTime start;

        start = DateTime.Now;
        var r1 = list1.Zip(list2, (a, b) => new { a, b }).ToList();
        var time1 = DateTime.Now - start;

        start = DateTime.Now;
        var r2 = list1.Select((l1, i) => new { a = l1, b = list2[i]}).ToList();
        var time2 = DateTime.Now - start;

        start = DateTime.Now;
        var r3 = new int[0].Select(i => new { a = 0, b = 0 }).ToList();
        //  Easy out-of-bounds prevention not offered in solution #2 (if list2 has fewer items)
        int max = Math.Max(list1.Count, list2.Count);
        for (int i = 0; i < max; i++)
            r3.Add(new { a = list1[i], b = list2[i] });
        var time3 = DateTime.Now - start;

        Debug.WriteLine("r1 == r2: {0}", r1.SequenceEqual(r2));
        Debug.WriteLine("r1 == r3: {0}", r1.SequenceEqual(r3));
        Debug.WriteLine("time1 {0}", time1);
        Debug.WriteLine("time2 {0}", time2);
        Debug.WriteLine("time3 {0}", time3);
const int Max=100000;
var rnd=新随机数();
var list1=Enumerable.Range(1,Max).Select(r=>rnd.Next(Max)).ToList();
var list2=Enumerable.Range(1,Max).Select(r=>rnd.Next(Max)).ToList();
日期时间开始;
start=DateTime.Now;
var r1=list1.Zip(list2,(a,b)=>new{a,b}).ToList();
var time1=DateTime.Now-start;
start=DateTime.Now;
var r2=list1.Select((l1,i)=>new{a=l1,b=list2[i]});
var time2=DateTime.Now-start;
start=DateTime.Now;
var r3=newint[0]。选择(i=>new{a=0,b=0})。ToList();
//解决方案#2中未提供简单的越界预防(如果列表2中的项目较少)
int max=Math.max(list1.Count,list2.Count);
对于(int i=0;i
输出为:

r1==r2:True
r1==r3:True
时间1 00:00:00.0100071
时间2 00:00:00.0170138
时间3 00:00:00.0040028

当然,在这种情况下,时间几乎不值得注意(对人类的感知),因此它可以归结为偏好,但知道#3是最快的,我倾向于在关键性能领域使用它,在这些领域中,类型更复杂,或者枚举数可能更大

另外,请注意使用3时的区别:

        const int Max = 100000;
        var rnd = new Random();
        var list1 = Enumerable.Range(1, Max).Select(r => rnd.Next(Max)).ToList();
        var list2 = Enumerable.Range(1, Max).Select(r => rnd.Next(Max)).ToList();
        var list3 = Enumerable.Range(1, Max).Select(r => rnd.Next(Max)).ToList();

        DateTime start;

        start = DateTime.Now;
        var r1 = list1.Zip(list2, (a, b) => new { a, b }).Zip(list3, (ab, c) => new { ab.a, ab.b, c }).ToList();
        var time1 = DateTime.Now - start;

        start = DateTime.Now;
        var r2 = list1.Select((l1, i) => new { a = l1, b = list2[i], c = list3[i] }).ToList();
        var time2 = DateTime.Now - start;

        start = DateTime.Now;
        var r3 = new int[0].Select(i => new { a = 0, b = 0, c = 0 }).ToList();
        //  Easy out-of-bounds prevention not offered in solution #2 (if list2 or list3 have fewer items)
        int max = new int[] { list1.Count, list2.Count, list3.Count }.Max();
        for (int i = 0; i < max; i++)
            r3.Add(new { a = list1[i], b = list2[i], c = list3[i] });
        var time3 = DateTime.Now - start;

        Debug.WriteLine("r1 == r2: {0}", r1.SequenceEqual(r2));
        Debug.WriteLine("r1 == r3: {0}", r1.SequenceEqual(r3));
        Debug.WriteLine("time1 {0}", time1);
        Debug.WriteLine("time2 {0}", time2);
        Debug.WriteLine("time3 {0}", time3);
const int Max=100000;
var rnd=新随机数();
var list1=Enumerable.Range(1,Max).Select(r=>rnd.Next(Max)).ToList();
var list2=Enumerable.Range(1,Max).Select(r=>rnd.Next(Max)).ToList();
var list3=Enumerable.Range(1,Max).Select(r=>rnd.Next(Max)).ToList();
日期时间开始;
start=DateTime.Now;
var r1=list1.Zip(list2,(a,b)=>new{a,b}).Zip(list3,(ab,c)=>new{ab.a,ab.b,c}).ToList();
var time1=DateTime.Now-start;
start=DateTime.Now;
var r2=list1.Select((l1,i)=>new{a=l1,b=list2[i],c=list3[i]});
var time2=DateTime.Now-start;
start=DateTime.Now;
var r3=newint[0]。选择(i=>new{a=0,b=0,c=0});
//轻松的
        const int Max = 100000;
        var rnd = new Random();
        var list1 = Enumerable.Range(1, Max).Select(r => rnd.Next(Max)).ToList();
        var list2 = Enumerable.Range(1, Max).Select(r => rnd.Next(Max)).ToList();

        DateTime start;

        start = DateTime.Now;
        var r1 = list1.Zip(list2, (a, b) => new { a, b }).ToList();
        var time1 = DateTime.Now - start;

        start = DateTime.Now;
        var r2 = list1.Select((l1, i) => new { a = l1, b = list2[i]}).ToList();
        var time2 = DateTime.Now - start;

        start = DateTime.Now;
        var r3 = new int[0].Select(i => new { a = 0, b = 0 }).ToList();
        //  Easy out-of-bounds prevention not offered in solution #2 (if list2 has fewer items)
        int max = Math.Max(list1.Count, list2.Count);
        for (int i = 0; i < max; i++)
            r3.Add(new { a = list1[i], b = list2[i] });
        var time3 = DateTime.Now - start;

        Debug.WriteLine("r1 == r2: {0}", r1.SequenceEqual(r2));
        Debug.WriteLine("r1 == r3: {0}", r1.SequenceEqual(r3));
        Debug.WriteLine("time1 {0}", time1);
        Debug.WriteLine("time2 {0}", time2);
        Debug.WriteLine("time3 {0}", time3);
        const int Max = 100000;
        var rnd = new Random();
        var list1 = Enumerable.Range(1, Max).Select(r => rnd.Next(Max)).ToList();
        var list2 = Enumerable.Range(1, Max).Select(r => rnd.Next(Max)).ToList();
        var list3 = Enumerable.Range(1, Max).Select(r => rnd.Next(Max)).ToList();

        DateTime start;

        start = DateTime.Now;
        var r1 = list1.Zip(list2, (a, b) => new { a, b }).Zip(list3, (ab, c) => new { ab.a, ab.b, c }).ToList();
        var time1 = DateTime.Now - start;

        start = DateTime.Now;
        var r2 = list1.Select((l1, i) => new { a = l1, b = list2[i], c = list3[i] }).ToList();
        var time2 = DateTime.Now - start;

        start = DateTime.Now;
        var r3 = new int[0].Select(i => new { a = 0, b = 0, c = 0 }).ToList();
        //  Easy out-of-bounds prevention not offered in solution #2 (if list2 or list3 have fewer items)
        int max = new int[] { list1.Count, list2.Count, list3.Count }.Max();
        for (int i = 0; i < max; i++)
            r3.Add(new { a = list1[i], b = list2[i], c = list3[i] });
        var time3 = DateTime.Now - start;

        Debug.WriteLine("r1 == r2: {0}", r1.SequenceEqual(r2));
        Debug.WriteLine("r1 == r3: {0}", r1.SequenceEqual(r3));
        Debug.WriteLine("time1 {0}", time1);
        Debug.WriteLine("time2 {0}", time2);
        Debug.WriteLine("time3 {0}", time3);
static class EnumerableExtensions {

  public static IEnumerable<TResult> Zip<TSource, TResult>(
    this IEnumerable<IEnumerable<TSource>> source,
    Func<IEnumerable<TSource>, TResult> resultSelector
  ) {
    if (source == null)
      throw new ArgumentNullException("source");
    if (resultSelector == null)
      throw new ArgumentNullException("resultSelector");

    var enumerators = new List<IEnumerator<TSource>>();
    try {
      foreach (var enumerable in source) {
        if (enumerable == null)
          throw new ArgumentNullException();
        enumerators.Add(enumerable.GetEnumerator());
      }

      while (enumerators.Aggregate(true, (moveNext, enumerator) => moveNext && enumerator.MoveNext()))
        yield return resultSelector(enumerators.Select(enumerator => enumerator.Current));
    }
    finally {
      foreach (var enumerator in enumerators)
        enumerator.Dispose();
    }
  }

}
var reds = new[] { 0x00, 0x03, 0x06, 0x08, 0x09 };
var greens = new[] { 0x00, 0x05, 0x06, 0x07, 0x0a };
var blues = new[] { 0x00, 0x02, 0x03, 0x05, 0x09 };
var colors = new[] { reds, greens, blues }
  .Zip(rgb => new RGB(rgb.First(), rgb.Skip(1).First(), rgb.Skip(2).First()));
public static IEnumerable<TResult> Zip<T, TResult>(this IEnumerable<T>[] sequences, Func<T[], TResult> resultSelector)
{
    var enumerators = sequences.Select(s => s.GetEnumerator()).ToArray();
    while(enumerators.All(e => e.MoveNext()))
        yield return resultSelector(enumerators.Select(e => e.Current).ToArray());
}
List_A.Select(a => a.List_B).SelectMany(s => s).ToList();