Getting pair-set using LINQ

12,478

Solution 1

This will give you an array of anonymous "pair" objects with A and B properties corresponding to the pair elements.

var pairs = list.Where( (e,i) => i < list.Count - 1 )
                .Select( (e,i) => new { A = e, B = list[i+1] }  );

Solution 2

The most elegant way with LINQ: list.Zip(list.Skip(1), Tuple.Create)

A real-life example: This extension method takes a collection of points (Vector2) and produces a collection of lines (PathSegment) needed to 'join the dots'.

static IEnumerable<PathSegment> JoinTheDots(this IEnumerable<Vector2> dots)
{
    var segments = dots.Zip(dots.Skip(1), (a,b) => new PathSegment(a, b));
    return segments;
}

Solution 3

You can use a for loop:

var pairs = new List<int[]>();
for(int i = 0; i < list.Length - 1; i++)
    pairs.Add(new [] {list[i], list[i + 1]);

You can also use LINQ, but it's uglier:

var pairs = list.Take(list.Count - 1).Select((n, i) => new [] { n, list[i + 1] });

EDIT: You can even do it on a raw IEnumerable, but it's much uglier:

var count = list.Count();
var pairs = list
    .SelectMany((n, i) => new [] { new { Index = i - 1, Value = n }, new { Index = i, Value = n } })
    .Where(ivp => ivp.Index >= 0 && ivp.Index < count - 1)    //We only want one copy of the first and last value
    .GroupBy(ivp => ivp.Index, (i, ivps) => ivps.Select(ivp => ivp.Value));

Solution 4

More general would be:

    public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> values, int count, Func<TSource[], TResult> pairCreator)
    {
        if (count < 1) throw new ArgumentOutOfRangeException("count");
        if (values == null) throw new ArgumentNullException("values");
        if (pairCreator == null) throw new ArgumentNullException("pairCreator");
        int c = 0;
        var data = new TSource[count];
        foreach (var item in values)
        {
            if (c < count)
                data[c++] = item;
            if (c == count)
            {
                yield return pairCreator(data);
                c = 0;
            }
        }
    }

Solution 5

Following solution uses zip method. Zip originalList and originalList.Skip(1) so that one gets desired result.

    var adjacents =
            originalList.Zip(originalList.Skip(1),
                             (a,b) => new {N1 = a, N2 = b});
Share:
12,478

Related videos on Youtube

user160677
Author by

user160677

Updated on April 17, 2022

Comments

  • user160677
    user160677 about 2 years

    When i have a list

    IList<int> list = new List<int>();
    list.Add(100);
    list.Add(200);
    list.Add(300);
    list.Add(400);
    list.Add(500);
    

    What is the way to extract a pairs

    Example : List elements {100,200,300,400,500}
    
    Expected Pair : { {100,200} ,{200,300} ,{300,400} ,{400,500} }
    
    • leppie
      leppie over 14 years
      Please specify your problem better. What you have now can mean one of any number of things...
    • SLaks
      SLaks over 14 years
      Do you want to operate on a raw IEnumerable or only an IList<T>? If so, see my edit.
  • GameKyuubi
    GameKyuubi over 7 years
    Can someone explain what this does? It's quite dense.
  • tvanfosson
    tvanfosson over 7 years
    @GameKyuubi the (e,i) notation represents the signature that takes both the element and the index of the element. The Where clause allows all but the last element in the sequence. The Select clause creates a new anonymous object with the A element assigned the original element in the sequence and the B element assigned the following element in the sequence. That is, if e represents the ith element at each iteration, then B gets the i+1th element.