2009-10-26 17 views
13

Kiedy mam listęPierwsze parze zestaw przy użyciu LINQ

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

Jaki jest sposób wyodrębnić pary

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

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

Proszę podać swój problem lepiej. Co masz teraz może oznaczać jedną z wielu rzeczy ... – leppie

+0

Czy chcesz działać na surowym 'IEnumerable' lub tylko' IList '? Jeśli tak, zobacz moją edycję. – SLaks

Odpowiedz

24

To daje szereg anonimowych „pair” obiektów z i B właściwości odpowiadające elementom par.

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

Czy ktoś może wyjaśnić, co to robi? Jest dość gęsty. – GameKyuubi

+1

@GameKyuubi notacja '(e, i)' reprezentuje podpis, który przyjmuje zarówno element, jak i indeks elementu. Klauzula 'Where' pozwala wszystkim oprócz ostatniego elementu w sekwencji. Klauzula 'Select' tworzy nowy anonimowy obiekt z elementem" A ", któremu przypisano oryginalny element w sekwencji, a elementowi' B' przypisano następujący element w sekwencji. Oznacza to, że jeśli 'e' reprezentuje element' i'th w każdej iteracji, to 'B' otrzymuje element' i + 1'th. – tvanfosson

8

Można użyć pętli for:

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

Można również użyć LINQ, ale to brzydsze:

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

EDIT: Można nawet zrobić na surowy IEnumerable, ale jest znacznie brzydsza:

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

Off szczycie mojej głowy i całkowicie niesprawdzone:

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

Więcej ogóle byłoby:

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

Najbardziej elegancki sposób z LINQ: list.Zip(list.Skip(1), Tuple.Create)

Prawdziwa natura przykład: Ta metoda rozszerzenia pobiera kolekcję punktów (Vector2) i tworzy kolekcję linii (PathSegment) potrzebnych do "dołączenia kropek".

1

Następujące rozwiązanie wykorzystuje metodę zip. Zip originalList i originalList.Skip (1), aby uzyskać pożądany wynik.

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

Korzystanie .Windowed() z MoreLINQ:

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