Greeny
Greeny

Reputation: 1951

Aggregate sub-lists using LINQ

I have a list of objects (i.e. integers) and I want to aggregate sub-lists with LINQ.

For example:

Original list: [ 1, 4, 5, 3, 4, 10, 4, 12 ]

Sub-lists: [ [1,4,5,3], [4,5,3,4], [5,3,4,10], [3,4,10,4], [4,10,4,12] ]

Result (Aggregated List): [ 5, 5, 10, 10, 12 ]

I want to create the maximum of a sub-list for each element containing itself and the following n = 3 elements. Is this possible with LINQ or do I need to create my own aggregation mechanism?

Thanks in advance,Christian

Upvotes: 1

Views: 742

Answers (4)

Arsen Mkrtchyan
Arsen Mkrtchyan

Reputation: 50752

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());

Or in one line

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());

Upvotes: 6

3dGrabber
3dGrabber

Reputation: 5074

The Sub-lists intermediate result can be constructed with a "Sliding Window" function.

The desired Result then is the function Max() mapped over the windows with 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 ]


Efficient Window function:

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();
    }
}

Upvotes: 0

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236328

var result = sublists.Select(sl => sl.Max());
// [5,5,10,10,12]

Creating sub-lists:

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]]

Upvotes: 1

nima
nima

Reputation: 6733

    IEnumerable<int[]> GetLists (int[] list, int size )
    {
       return Enumerable.Range(0, list.Length - size + 1).Select(x => list.Skip(x).Take(size).ToArray());
    } 

Sample:

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

Upvotes: 0

Related Questions