【问题标题】:How to Zip two Lists of different size to create a new list that is same as the size of the longest amongst the original lists?如何压缩两个不同大小的列表以创建一个与原始列表中最长的大小相同的新列表?
【发布时间】:2020-11-19 16:29:19
【问题描述】:

我有两个不同大小的 C# 列表,例如

List<int> list1 = new List<int>{1,2,3,4,5,6,7};
List<int> list2 = new List<int>{4,5,6,7,8,9};

我想使用 linq Zip 方法将这两个组合成一个大小为 list1 的元组列表。这是我正在寻找的结果列表

{(1,4), (2,5), (3,6), (4,7), (5,8), (6,9), (7,0)}  //this is of type List<(int,int)

由于 list1 的最后一项在 list2 中没有对应项,因此我用默认值填充结果列表的最后一项(在本例中为 0,因为在我的情况下它永远不会出现在任何原始列表中)。

有没有办法单独使用 linq Zip 方法来实现这一点?

【问题讨论】:

  • 用默认值填充较短的列表?另外:你真的应该考虑使用int?,这样你就可以区分0和null
  • 好吧,在我的情况下,0 永远不会出现在 list1 或 list2 中。我已经更新了问题以反映相同的情况。

标签: c# .net linq generic-list


【解决方案1】:

您可以使用Concat 使它们的大小相同,然后将其压缩:

var zipped = list1.Concat(Enumerable.Repeat(0,Math.Max(list2.Count-list1.Count,0)))
        .Zip(list2.Concat(Enumerable.Repeat(0,Math.Max(list1.Count-list2.Count,0))),
            (a,b)=>(a,b));

或者创建一个扩展方法:

public static class ZipExtension{
    public static IEnumerable<TResult> Zip<TFirst,TSecond,TResult>(
        this IEnumerable<TFirst> first,
        IEnumerable<TSecond> second, 
        Func<TFirst,TSecond,TResult> func, 
        TFirst padder1,
        TSecond padder2)
    {
        var firstExp = first.Concat(
            Enumerable.Repeat(
                padder1, 
                Math.Max(second.Count()-first.Count(),0)
            )
        );
        var secExp = second.Concat(
            Enumerable.Repeat(
                padder2,
                Math.Max(first.Count()-second.Count(),0)
            )
        );
        return firstExp.Zip(secExp, (a,b) => func(a,b));
    }
}

所以你可以这样使用:

//last 2 arguments are the padder values for list1 and list2
var zipped = list1.Zip(list2, (a,b) => (a,b), 0, 0); 

【讨论】:

    【解决方案2】:

    有一个有用且流行的MoreLinq 库。安装并使用。

    using MoreLinq;
    
    var result = list1.ZipLongest(list2, (x, y) => (x, y));
    

    【讨论】:

      【解决方案3】:

      使用 Zip 功能试试这个-

      static void Main(string[] args)
          {
              List<int> firstList = new List<int>() { 1, 2, 3, 4, 5, 6, 0, 34, 56, 23 };
              List<int> secondList = new List<int>() { 4, 5, 6, 7, 8, 9, 1 };
      
              int a = firstList.Count;
              int b = secondList.Count;
      
              for (int k = 0; k < (a - b); k++)
                  {
                      if(a>b)
                          secondList.Add(0);
                      else
                          firstList.Add(0);
                  }
      
              var zipArray = firstList.Zip(secondList, (c, d) => c + " " + d);
              foreach(var item in zipArray)
              {
                  Console.WriteLine(item);
              }
              Console.Read();
          }
      

      或者您可以通过安装 MoreLinq nuget 包来使用 ZipLongest 函数进行尝试-

      static void Main(string[] args)
          {
              List<int> firstList = new List<int>() { 1, 2, 3, 4, 5, 6, 0, 34, 56, 23 };
              List<int> secondList = new List<int>() { 4, 5, 6, 7, 8, 9, 1 };
      
              var zipArray = firstList.ZipLongest(secondList, (c, d) => (c,d));
              foreach (var item in zipArray)
              {
                  Console.WriteLine(item);
              }
              Console.Read();
          }
      

      【讨论】:

        【解决方案4】:

        试试这个代码-

        static void Main(string[] args)
            {
                List<int> firstList=new List<int>() { 1, 2, 3, 4, 5, 6,0,34,56,23};
                List<int> secondList=new List<int>() { 4, 5, 6, 7, 8, 9,1};
        
                int a = firstList.Count;
                int b = secondList.Count;
        
                if (a > b)
                {
                    for(int k=0;k<(a-b);k++)
                        secondList.Add(0);
                }
                else
                {
                    for (int k = 0; k < (b-a); k++)
                        firstList.Add(0);
                }
        
                for(int i=0;i<firstList.Count;i++)
                {
                    for(int j=0;j<=secondList.Count;j++)
                    {
                        if(i==j)
                            Console.Write($"({Convert.ToInt32(firstList[i])},{ Convert.ToInt32(secondList[j])})" + "");
                    }
                }
                Console.Read();
            }
        

        【讨论】:

        • 谢谢,这给了我一些想法。但我认为用 Zip 函数替换 for 块会减少代码量。还是我在这里遗漏了什么?
        • 是的,我同意你的观点,请使用 Zip 函数尝试上面的代码。
        猜你喜欢
        • 2013-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-24
        • 2021-08-24
        • 1970-01-01
        • 2023-02-10
        相关资源
        最近更新 更多