Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 列表<;字符串[]>;通过Linq确定最大长度_C#_Linq_List - Fatal编程技术网

C# 列表<;字符串[]>;通过Linq确定最大长度

C# 列表<;字符串[]>;通过Linq确定最大长度,c#,linq,list,C#,Linq,List,我有以下结构 List<string[]> sList = new List<string[]>() { new[] { "x", "xxx", "xxxx" }, //1,3,4 new[] { "x", "xx", "xx" }, //1,2,2 new[] { "xxxxxx", "xx", "xx" } //6,2,2 }; 是否有一种简单的Linq方法 我的努力(工作但不使用Linq): 列表结果=新列表(); foreach

我有以下结构

List<string[]> sList = new List<string[]>() {
    new[] { "x", "xxx", "xxxx" },  //1,3,4
    new[] { "x", "xx", "xx" },     //1,2,2
    new[] { "xxxxxx", "xx", "xx" } //6,2,2
};
是否有一种简单的Linq方法

我的努力(工作但不使用Linq):

列表结果=新列表();
foreach(表中的字符串[]行)
{
for(int i=0;ii)
{
if(结果[i]<行[i].长度)
{
结果[i]=行[i]。长度;
}
}
其他的
{
结果。插入(i,行[i]。长度);
}
}
}
行/列的数量是动态的,但每行的列数相同。

一种方法:

int maxColumns = sList.Max(arr => arr.Length);
List<int> Result = Enumerable.Range(0, maxColumns)
    .Select(i => sList.Max(arr => (arr.ElementAtOrDefault(i) ?? "").Length))
    .ToList();

这是我能想到的最好的办法:

List<int> Result = sList.First().Select((x, i) => sList.Max(y => y[i].Length)).ToList();
List Result=sList.First().Select((x,i)=>sList.Max(y=>y[i].Length)).ToList();
一条线的加分

说明: 既然你说它们都有相同数量的元素,那么就从第一行开始循环。使用索引从每个其他行中获取该元素,获取长度,然后获取其最大值。

假设所有“行”的项数(“列”)相同:

这就是我所拥有的:-

  int arrayLength = sList.First().Length;
  List<int> result = sList.SelectMany(x => x)
                           .Select((v, i) => new { Value = v, Index = i % arrayLength  })
                           .GroupBy(x => x.Index)
                           .Select(x => x.Max(z => z.Value.Length))
                           .ToList();
int arrayLength=sList.First().Length;
列表结果=sList.SelectMany(x=>x)
.Select((v,i)=>new{Value=v,Index=i%arrayLength})
.GroupBy(x=>x.Index)
.选择(x=>x.Max(z=>z.Value.Length))
.ToList();
说明:-展平列表,投影其值和索引(索引根据列长度计算),按索引分组并选择最大长度的值。

以下是使用以下方法的方法:

这样做的前提是每个集合都有相同数量的项目

工作原理:
  • 首先,我们只取字符串的长度,因此从概念上讲,我们使用的是
    IEnumerable
    ,因此我们的集合如下所示:

    {{1, 3, 4},
     {1, 2, 2},
     {6, 2, 2}}
    
    List<Int> seed = ???
    Func<IEnumerable<Int>, IEnumerable<Int>, IEnumerable<Int>> accumulator  = ???
    llist.Aggregate(seed, accumulator);
    
    (这是不准确的-因为我们从未实际拥有此集合-根据需要计算每行的长度。)

  • 接下来,我们使用
    Aggregate
    组合向量:

    • 我们有
      {1,3,4}
      {1,2,2}
    • 这两个集合:
      {{1,2},{3,2},{4,2}
    • 对每一对应用
      Math.Max
      ,并获得
      {2,3,4}
  • {2,3,4}
    {6,2,2}
    重复上述操作,然后接收
    {6,3,4}
赞成的意见:
  • 适用于单行
  • 仅在集合上迭代一次
  • 不对具体实现(数组列表)进行任何假设-可以使用任何
    IEnumerable
    ,而不依赖
    [i]
    ElementAtOrDefault
  • 您已请求Linq解决方案
欺骗:
  • 有点复杂
  • 如果行的长度不同,
    Zip
    将不符合预期(返回最短的长度,而不是最长的长度)

聚合结果的一般方法是
聚合
扩展方法

tl;rd对于最简单的情况:

    slist.Select(row => row.Select(str => str.Length))
         .Aggregate(l, r) => l.Zip(r, Math.Max);
首先,让我们以我们想要的形式获取数据:长度列表

var llist = slist.Select(row => row.Select(str => str.Length));
现在我们有一个长度列表。更容易相处

Aggregate的工作原理是保持一些运行总计,并运行一个参数为Aggregate和下一行的函数,从而生成一个新的聚合。您可以选择提供种子值。看起来是这样的:

{{1, 3, 4},
 {1, 2, 2},
 {6, 2, 2}}
List<Int> seed = ???
Func<IEnumerable<Int>, IEnumerable<Int>, IEnumerable<Int>> accumulator  = ???
llist.Aggregate(seed, accumulator);
如果列数不变,我们可以使用内置Zip

llist.Aggregate((l, r) => l.Zip(r, Math.Max));

(1) 在这个问题的范围之外,还有一个更普遍的过载

IEnumerable<TResult, TLeft, TRight> ZipAll(IEnumerable<TLeft> left, IENumerable<TRight> right, Func<TResult, TLeft, TRight> selector, Func<TResult, TLeft> leftSelector, Func<Tresult, TRight> rightselector) {
   var le = left.GetEnumerator;
   var re = right.GetEnumerator;

   while(le.MoveNext()){
     if (re.MoveNext()) {
       yield return selector(le.Current, re.Current);
     } else {
       yield return leftSelector(le.Current);
     }
   }

   while(re.MoveNext()) yield return rightSelector(re.Current);
}
IEnumerable ZipAll(IEnumerable left,IEnumerable right,Func选择器,Func leftSelector,Func rightselector){
var le=left.GetEnumerator;
var re=right.GetEnumerator;
while(le.MoveNext()){
if(re.MoveNext()){
收益率返回选择器(le电流、re电流);
}否则{
收益返回左选择器(当前值);
}
}
而(re.MoveNext())则返回rightSelector(re.Current);
}
有了这个,我们可以用左、右投影作为身份函数来写我们早期的ZipAll

IEnumerable<T> ZipAll(this IEnumerable<T> left, IENumerable<T> right, Func<T, T, T> selector) {
    return ZipAll(left, right, selector, id => id, id => id);
 }
IEnumerable ZipAll(此IEnumerable左、IEnumerable右、函数选择器){
返回ZipAll(左、右、选择器,id=>id,id=>id);
}

令人惊讶的是,没有任何好的(有效的)答案

1) 不要使用LINQ。尝试一种简单易读的程序解决方案
2) 如果出于某种原因您想使用LINQ,至少要使其高效

下面是我的示例代码的结果

使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
命名空间控制台应用程序9
{
内部课程计划
{
私有静态void Main(字符串[]args)
{
Random rand=新的Random();
int maxColumnLength=10;
整数行数=100000;
int colNumber=300;
列表输入=新列表();
for(int i=0;iList<Int> seed = new List<Int>();
Func<List<Int>, List<Int>, List<Int>> accumulator  = ???
llist.Aggregate(seed, accumulator);
private IEnumerable<Int> accumulate(aggregate, row){
  aggregate.Zip(row, (i1, i2) => Math.max(i1, i2));
}
  IEnumerable<T> ZipAll(IEnumerable<T> left, IENumerable<T> right, Func<T, T, T> selector) {
   var le = left.GetEnumerator;
   var re = right.GetEnumerator;

   while(le.MoveNext()){
     if (re.MoveNext()) {
       yield return selector(le.Current, re.Current);
     } else {
       yield return le.Current;
     }
   }

   while(re.MoveNext()) yield return re.Current;
}
List<Int> seed = new List<Int>();
Func<List<Int>, List<Int>, List<Int>> accumulator = (l, r) => ZipAll(l, r, Math.Max);
llist.Aggregate(seed, accumulator);
llist.Aggregate(new List<Int>(), (l, r) => ZipAll(l, r, Math.Max));
llist.Aggregate((l, r) => ZipAll(l, r, Math.Max));
llist.Aggregate((l, r) => l.Zip(r, Math.Max));
IEnumerable<TResult, TLeft, TRight> ZipAll(IEnumerable<TLeft> left, IENumerable<TRight> right, Func<TResult, TLeft, TRight> selector, Func<TResult, TLeft> leftSelector, Func<Tresult, TRight> rightselector) {
   var le = left.GetEnumerator;
   var re = right.GetEnumerator;

   while(le.MoveNext()){
     if (re.MoveNext()) {
       yield return selector(le.Current, re.Current);
     } else {
       yield return leftSelector(le.Current);
     }
   }

   while(re.MoveNext()) yield return rightSelector(re.Current);
}
IEnumerable<T> ZipAll(this IEnumerable<T> left, IENumerable<T> right, Func<T, T, T> selector) {
    return ZipAll(left, right, selector, id => id, id => id);
 }
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace ConsoleApplication9
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Random rand = new Random();
            int maxColumnLength = 10;
            int rowNumber = 100000;
            int colNumber = 300;
            List<string[]> input = new List<string[]>();
            for (int i = 0; i < rowNumber; i++)
            {
                string[] row = new string[colNumber];
                for (int j = 0; j < colNumber; j++)

                    row[j] = new string('x', rand.Next(maxColumnLength));

                input.Add(row);
            }

            var result = Time(SimpleIteration, input, "Simple Iteration");

            var result2 = Time(SimpleIterationWithLinq, input, "Simple Iteration LINQ");

            var result3 = Time(AcceptedAnswer, input, "Accepted Answer");

            var result4 = Time(TomDoesCode, input, "TomDoesCode");

            //var result5 = Time(Kobi, input, "Kobi"); //StackOverflow

            var result6 = Time(Konamiman, input, "Konamiman");

            var result7 = Time(RahulSingh, input, "RahulSingh");

            System.Console.ReadLine();
        }

        private static List<int> SimpleIteration(List<string[]> input)
        {
            int[] maxPerColumn = new int[input.First().Length];
            for (int i = 0; i < maxPerColumn.Length; i++)
                maxPerColumn[i] = -1;

            foreach (var row in input)
            {
                for (int i = 0; i < row.Length; i++)
                    if (maxPerColumn[i] < row[i].Length)
                        maxPerColumn[i] = row[i].Length;
            }

            return maxPerColumn.ToList();
        }

        private static List<int> SimpleIterationWithLinq(List<string[]> input)
        {
            return input.Aggregate(new int[input.First().Length], (maxPerColumn, row) =>
             {
                 for (int i = 0; i < row.Length; i++)
                     if (maxPerColumn[i] < row[i].Length)
                         maxPerColumn[i] = row[i].Length;

                 return maxPerColumn;
             }).ToList();
        }

        private static List<int> AcceptedAnswer(List<string[]> input)
        {
            return Enumerable.Range(0, input.First().Length)
                             .Select(i => input.Max(arr => arr[i].Length))
                             .ToList();
        }

        private static List<int> TomDoesCode(List<string[]> input)
        {
            return input.First().Select((x, i) => input.Max(y => y[i].Length)).ToList();
        }

        private static List<int> Kobi(List<string[]> input)
        {
            return input.Select(strings => strings.Select(s => s.Length))
                      .Aggregate((prev, current) => prev.Zip(current, Math.Max)).ToList();
        }

        private static List<int> Konamiman(List<string[]> input)
        {
            var rowLength = input[0].Length;
            return Enumerable.Range(0, rowLength)
                .Select(index => input.Select(row => row[index].Length).Max())
                .ToList();
        }

        private static List<int> RahulSingh(List<string[]> input)
        {
            int arrayLength = input.First().Length;
            return input.SelectMany(x => x)
                                     .Select((v, i) => new { Value = v, Index = i % arrayLength })
                                     .GroupBy(x => x.Index)
                                     .Select(x => x.Max(z => z.Value.Length))
                                     .ToList();
        }

        private static List<int> Time(Func<List<string[]>, List<int>> act, List<string[]> input, string methodName)
        {
            Stopwatch s = Stopwatch.StartNew();
            var result = act(input);
            s.Stop();
            Console.WriteLine(methodName.PadRight(25) + ":" + s.ElapsedMilliseconds + " ms");
            return result;
        }
    }
}