2009-10-26 13 views
13

Cuando tengo una listaConseguir par-set usando LINQ

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

¿Cuál es la forma de extraer unas pares

Example : List elements {100,200,300,400,500} 

Expected Pair : { {100,200} ,{200,300} ,{300,400} ,{400,500} } 
+0

favor, especifique su problema mejor. Lo que tiene ahora puede significar una de varias cosas ... – leppie

+0

¿Desea operar en un 'IEnumerable' sin formato o solo en un' IList '? Si es así, mira mi edición. – SLaks

Respuesta

24

Esto le dará una serie de "par" objetos anónimos con A y B propiedades correspondientes a los elementos de par.

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

¿Alguien puede explicar lo que hace? Es bastante denso – GameKyuubi

+1

@GameKyuubi la notación '(e, i)' representa la firma que toma tanto el elemento como el índice del elemento. La cláusula 'Where' permite todos menos el último elemento de la secuencia. La cláusula 'Seleccionar' crea un nuevo objeto anónimo con el elemento' A' asignado al elemento original en la secuencia y el elemento 'B' asigna el siguiente elemento en la secuencia. Es decir, si 'e' representa el elemento' i'th en cada iteración, entonces 'B' obtiene el elemento' i + 1'th. – tvanfosson

8

Puede utilizar un bucle:

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

También puede utilizar LINQ, pero es más feo:

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

EDITAR: Incluso puede hacerlo en una prima IEnumerable, pero es mucho más feo:

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

De la parte superior de mi cabeza y no está comprobado:

public static T Pairwise<T>(this IEnumerable<T> list) 
{ 
    T last; 
    bool firstTime = true; 
    foreach(var item in list) 
    { 
     if(!firstTime) 
      return(Tuple.New(last, item)); 
     else 
      firstTime = false; 
     last = item; 
    } 
} 
2

más general sería:

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; 
      } 
     } 
    } 
22

La forma más elegante, con LINQ: list.Zip(list.Skip(1), Tuple.Create)

Un ejemplo real: Este método de extensión toma una colección de puntos (Vector2) y produce una colección de líneas (PathSegment) necesarias para 'unir los puntos'.

1

La solución siguiente utiliza el método zip. Zip originalList y originalList.Skip (1) para obtener el resultado deseado.

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

Usando .Windowed() de MoreLINQ:

var source = new[] {100,200,300,400,500}; 
var result = source.Windowed(2).Select(x => Tuple.Create(x.First(),x.Last())); 
Cuestiones relacionadas