2009-10-26 13 views
13

quando ho una listaOttenere coppia-set utilizzando LINQ

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

Qual è il modo per estrarre una coppia

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

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

Si prega di specificare il vostro problema in maniera migliore. Quello che hai ora può significare uno di qualsiasi numero di cose ... – leppie

+0

Vuoi operare su un grezzo 'IEnumerable' o solo un' IList '? Se è così, vedi la mia modifica. – SLaks

risposta

24

questo vi darà una serie di anonimi "abbinare" oggetti con una e B proprietà corrispondenti agli elementi della coppia.

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

Qualcuno può spiegare cosa fa? È abbastanza denso. – GameKyuubi

+1

@GameKyuubi la notazione '(e, i)' rappresenta la firma che prende sia l'elemento che l'indice dell'elemento. La clausola 'Where' consente tutto tranne l'ultimo elemento nella sequenza. La clausola 'Select' crea un nuovo oggetto anonimo con l'elemento' A' assegnato all'elemento originale nella sequenza e l'elemento 'B' ha assegnato il seguente elemento nella sequenza. Cioè, se 'e' rappresenta l'elemento' i'th ad ogni iterazione, allora 'B' ottiene l'elemento' i + 1'th. – tvanfosson

8

È possibile utilizzare un ciclo for:

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

È anche possibile utilizzare LINQ, ma è più brutto:

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

EDIT: Si può anche farlo su un grezzo IEnumerable, ma è molto più brutto:

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

Fuori della parte superiore della mia testa e completamente testati:

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

più generale sarebbe:

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

Il modo più elegante con LINQ: list.Zip(list.Skip(1), Tuple.Create)

Un esempio concreto: Questo metodo di estensione prende una raccolta di punti (Vector2) e produce una raccolta di linee (PathSegment) necessarie per "unire i punti".

1

La seguente soluzione utilizza il metodo zip. Zip originalList e originalList.Skip (1) in modo da ottenere il risultato desiderato.

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

Utilizzando .Windowed() da MoreLINQ:

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