2010-12-16 7 views
11
var nums = new[]{ 1, 2, 3, 4, 5, 6, 7}; 
var pairs = /* some linq magic here*/ ; 

=> pares = {{1, 2}, {3, 4}, {5, 6}, {7, 0}}Linq a Objetos - retorno pares de números de la lista de números

Los elementos de pairs deben ser listas de dos elementos o instancias de alguna clase anónima con dos campos, algo así como new {First = 1, Second = 2}.

+1

duplicado exacto de la pregunta hecha por ti mismo http: // stackoverflow.com/questions/3575925/linq-to-return-all-pairs-of-elements-from-two-lists –

+0

@Jani No, no lo es. Eso es pedir un equivalente al método Zip() de Python (o Ruby) -> toma dos listas y hace una lista de tuplas. Esta pregunta se trata de particionar una sola lista. –

+2

@Cristi lo consiguió, lo siento –

Respuesta

3

Prueba esto:

int i = 0; 
var pairs = 
    nums 
    .Select(n=>{Index = i++, Number=n}) 
    .GroupBy(n=>n.Index/2) 
    .Select(g=>{First:g.First().Number, Second:g.Last().Number}); 
+4

que puedes hacer. Selecciona ((n, i) => ...) para obtener un contador automático –

0
var nums = new float[] { 1, 2, 3, 4, 5, 6, 7 }; 
var enumerable = 
     Enumerable 
      .Range(0, nums.Length) 
      .Where(i => i % 2 == 0) 
      .Select(i => 
      new { F = nums[i], S = i == nums.Length - 1 ? 0 : nums[i + 1] }); 
+0

-1: Eso no es lo que él pidió. –

+0

Eso devolverá los pares como {{1,2}, {2,3}, ...} – Yakimych

+0

@Lasse Funciona bien, ya que entiendo la pregunta, por favor revoque su voto negativo –

-1

esto da todos los pares posibles (vb.net):

Dim nums() = {1, 2, 3, 4, 5, 6, 7} 
Dim pairs = From a In nums, b In nums Where a <> b Select a, b 

Editar:

Dim allpairs = From a In nums, b In nums Where b - a = 1 Select a, b 
Dim uniquePairs = From p In allpairs Where p.a Mod 2 <> 0 Select p 

nota: el último par se faltante, trabajando en él

Editar:

unión uniquePairs con el par {nums.Last,0}

+0

Eso no es lo que pedí. –

+0

No noté que los pares estaban en seuqence. Edité la respuesta –

1

Esto podría ser un poco más general que usted requiere - puede establecer una costumbre itemsInGroup:

int itemsInGroup = 2; 
var pairs = nums. 
      Select((n, i) => new { GroupNumber = i/itemsInGroup, Number = n }). 
      GroupBy(n => n.GroupNumber). 
      Select(g => g.Select(n => n.Number).ToList()). 
      ToList(); 

EDIT:

Si desea agregar ceros (o algún otro número) en caso de que el último grupo sea de un tamaño diferente:

int itemsInGroup = 2; 
int valueToAppend = 0; 
int numberOfItemsToAppend = itemsInGroup - nums.Count() % itemsInGroup; 

var pairs = nums. 
      Concat(Enumerable.Repeat(valueToAppend, numExtraItems)). 
      Select((n, i) => new { GroupNumber = i/itemsInGroup, Number = n }). 
      GroupBy(n => n.GroupNumber). 
      Select(g => g.Select(n => n.Number).ToList()). 
      ToList(); 
+0

¡Genial! Una advertencia, el último elemento en parejas tendrá solo 1 elemento si la lista de números tiene un recuento impar. P.ej. nums = {1,2,3} => pairs = {{1, 2}, {3}} –

+0

Consulte la actualización para el caso general. Si solo necesita esto con dos elementos por grupo, puede hacer una comprobación más simple de 'nums.Count()' y anexar un '0' si es impar. – Yakimych

0
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7 }; 
var result = numbers.Zip(numbers.Skip(1).Concat(new int[] { 0 }), (x, y) => new 
     { 
      First = x, 
      Second = y 
     }).Where((item, index) => index % 2 == 0); 
+0

Siempre agregaré un elemento cuyo valor sea 0, se ignorará automáticamente si la longitud de los números es par. –

+0

No sabía que haya una versión de Where() que admita la indexación. +1 –

+0

Y funciona también para listas de longitud impar :) –

1

(advertencia: se ve feo)

var pairs = x.Where((i, val) => i % 2 == 1) 
      .Zip(
      x.Where((i, val) => i % 2 == 0), 
       (first, second) => 
       new 
       { 
        First = first, 
        Second = second 
       }) 
      .Concat(x.Count() % 2 == 1 ? new[]{ 
       new 
       { 
        First = x.Last(), 
        Second = default(int) 
       }} : null); 
+0

Robo de Danny Chen, puede agregar un elemento '0' al segundo argumento de Zip y así deshacerse de su último bloque .Concat (...). –

0
var w = 
     from ei in nums.Select((e, i) => new { e, i }) 
     group ei.e by ei.i/2 into g 
     select new { f = g.First(), s = g.Skip(1).FirstOrDefault() }; 
7

Ninguno de los métodos de LINQ defecto puede hacer esto con pereza y con una sola exploración. Comprimir la secuencia consigo mismo hace 2 escaneos y la agrupación no es totalmente floja. Su mejor opción es implementar directamente:

public static IEnumerable<T[]> Partition<T>(this IEnumerable<T> sequence, int partitionSize) { 
    Contract.Requires(sequence != null) 
    Contract.Requires(partitionSize > 0) 

    var buffer = new T[partitionSize]; 
    var n = 0; 
    foreach (var item in sequence) { 
     buffer[n] = item; 
     n += 1; 
     if (n == partitionSize) { 
      yield return buffer; 
      buffer = new T[partitionSize]; 
      n = 0; 
     } 
    } 
    //partial leftovers 
    if (n > 0) yield return buffer; 
} 
+0

Mirando todas las respuestas, parece que Linq no es el mejor enfoque aquí. Tu implementación es bastante limpia. –

+0

Debe ser 'public static IEnumerable Partition ...'. –

1
public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max) 
{ 
    return InSetsOf(source, max, false, default(T)); 
} 

public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max, bool fill, T fillValue) 
{ 
    var toReturn = new List<T>(max); 
    foreach (var item in source) 
    { 
     toReturn.Add(item); 
     if (toReturn.Count == max) 
     { 
      yield return toReturn; 
      toReturn = new List<T>(max); 
     } 
    } 
    if (toReturn.Any()) 
    { 
     if (fill) 
     { 
      toReturn.AddRange(Enumerable.Repeat(fillValue, max-toReturn.Count)); 
     } 
     yield return toReturn; 
    } 
} 

uso:

var pairs = nums.InSetsOf(2, true, 0).ToArray(); 
0
IList<int> numbers = new List<int> {1, 2, 3, 4, 5, 6, 7}; 
var grouped = numbers.GroupBy(num => 
{ 
    if (numbers.IndexOf(num) % 2 == 0) 
    { 
     return numbers.IndexOf(num) + 1; 
    } 
    return numbers.IndexOf(num); 
}); 

Si necesita la última pareja llena de cero sólo podría añadir que antes de hacer la agrupación si el listcount es impar.

if (numbers.Count() % 2 == 1) 
{ 
    numbers.Add(0); 
} 

Otro enfoque podría ser:

var groupedIt = numbers 
    .Zip(numbers.Skip(1).Concat(new[]{0}), Tuple.Create) 
    .Where((x,i) => i % 2 == 0); 

O utilizar MoreLinq que tiene una gran cantidad de extensiones útiles:

IList<int> numbers = new List<int> {1, 2, 3, 4, 5, 6, 7}; 
var batched = numbers.Batch(2); 
Cuestiones relacionadas