【问题标题】:Aggregate sub-lists using LINQ使用 LINQ 聚合子列表
【发布时间】:2014-02-17 12:22:43
【问题描述】:

我有一个对象列表(即整数),我想用 LINQ 聚合子列表。

例如:

原名单:[ 1, 4, 5, 3, 4, 10, 4, 12 ]

子列表: [ [1,4,5,3], [4,5,3,4], [5,3,4,10], [3,4,10,4], [4,10,4,12] ]

结果(聚合列表): [ 5, 5, 10, 10, 12 ]

我想为每个包含自身的元素和以下n = 3 元素创建最大的子列表。 LINQ 可以做到这一点,还是我需要创建自己的聚合机制?

提前致谢,克里斯蒂安

【问题讨论】:

  • 原始列表与“子列表”有什么关系?
  • 我假设它显示了如何创建子列表。但也看不出与问题有任何关系
  • 你的问题需要更清楚一点。你自己试过了吗?
  • 我收集子列表需要一个 int + 下一个 3 来创建一个列表
  • 子列表是每个元素的新列表,每个元素包含以下n = 3 元素。 [a,b,c,d,e,f] 将变为 [[a,b,c,d],[b,c,d,e],[c,d,e,f]]

标签: c# linq


【解决方案1】:
public IEnumerable<IEnumerable<int>> GetSubLists(int[] collection)
{
   for(int i = 0; i< collection.Length - 3; i++)
       yield return collection.Skip(i).Take(4);
}

GetSubLists(original).Select(l => l.Max());

或者一行

int[] original = {1, 4, 5, 3, 4, 10, 4, 12 };
int chunkCount = 4;
Enumerable.Range(0, original.Length - chunkCount + 1).Select(i => original.Skip(i).Take(chunkCount))
 .Select(l => l.Max());

【讨论】:

  • 您的最后一个方法生成{ 5, 5, 10 } 而不是{ 5, 5, 10, 10, 12 }。另外值得注意的是,在每次迭代中跳过原始列表中的所有项目是非常低效的
  • 糟糕,对,应该是 + 1 而不是 -1。谢谢,编辑,同意跳过,但我选择了数组,它没有适当的 GetRange 方法。对于小数组是可以的
  • GetSubLists 方法最后会生成小于 4 的块。 (new [] {1,2,3}).Take(4) 产生 {1,2,3}
  • 请避免将 l 作为变量名。很容易误认为 1 或 I。
  • 另外,正如 Sergey 指出的那样,重复的 Skip(x).Take(y) 效率非常低,因为它会导致 O(n^2) 行为。每个元素都迭代 n 次。
【解决方案2】:
var result = sublists.Select(sl => sl.Max());
// [5,5,10,10,12]

创建子列表:

List<int> original = new List<int> { 1, 4, 5, 3, 4, 10, 4, 12 };
int sublistSize = 4; 
// check if original size is greater than required sublistSize
var sublists = Enumerable.Range(0, original.Count - sublistSize + 1)
                         .Select(i => original.GetRange(i, sublistSize));

// [[1,4,5,3],[4,5,3,4],[5,3,4,10],[3,4,10,4],[4,10,4,12]]

【讨论】:

  • 有没有自动创建子列表的方法? list.MAGIC_METHOD_TO_CREATE_SUBLISTS.Select(sl =&gt; sl.Max())
  • @Greeny 不清楚您是否要创建子列表。通过创建子列表更新答案
【解决方案3】:
    IEnumerable<int[]> GetLists (int[] list, int size )
    {
       return Enumerable.Range(0, list.Length - size + 1).Select(x => list.Skip(x).Take(size).ToArray());
    } 

示例:

    var list = new[] {1, 4, 5, 3, 4, 10, 4, 12};
    var max = GetLists(list, 4).Select(x => x.Max()).ToArray();

【讨论】:

    【解决方案4】:

    Sub-lists 中间结果可以用“滑动窗口”函数构造。

    所需的Result 是函数Max() 映射到带有Select() 的窗口。

    var originalList = new [] {1, 4, 5, 3, 4, 10, 4, 12};
    var sublists     = originalList.Window(4);            // [ [1,4,5,3], [4,5,3,4], ... ]
    var result       = sublists.Select(Enumerable.Max);   // [ 5, 5, 10, 10, 12 ]
    


    高效Window函数:

    public static IEnumerable<IEnumerable<T>> Window<T>(this IEnumerable<T> source, 
                                                                        int windowSize)
    {
        if(windowSize < 1) throw new ArgumentException("windowSize must positive", "windowSize");
    
        var q = new Queue<T>(windowSize);
        foreach(var e in source)
        {
             q.Enqueue(e);
             if(q.Count < windowSize) continue; // queue not full yet
    
             yield return q;
             q.Dequeue();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-06
      相关资源
      最近更新 更多