¿Hay una buena manera de dividir una colección en n
partes con LINQ? No necesariamente de manera uniforme, por supuesto.
Es decir, quiero dividir la colección en subcolecciones, cada una de las cuales contiene un subconjunto de los elementos, donde la última colección puede ser desigual.
c#
.net
linq
data-structures
Simon_Weaver
fuente
fuente
Respuestas:
Un linq puro y la solución más simple es como se muestra a continuación.
fuente
.AsEnumerable()
no es necesario, IGrouping <T> ya es un IEnumerable <T>.EDITAR: Bien, parece que leí mal la pregunta. Lo leí como "piezas de longitud n" en lugar de "n piezas". Doh! Considerando eliminar la respuesta ...
(Respuesta original)
No creo que haya una forma integrada de particionar, aunque tengo la intención de escribir una en mi conjunto de adiciones a LINQ to Objects. Marc Gravell tiene una implementación aquí, aunque probablemente lo modificaría para devolver una vista de solo lectura:
fuente
yield return
. Requiere un lote para estar en la memoria a la vez, pero eso es todo.fuente
var dept = {1,2,3,4,5}
. Después de dividir el resultado es comodept1 = {1,3,5}
ydept2 = { 2,4 }
dóndeparts = 2
. Pero el resultado que necesito esdept1 = {1,2,3}
ydept2 = {4,5}
int columnLength = (int)Math.Ceiling((decimal)(list.Count()) / parts);
luego hice la división con.GroupBy(x => x.index / columnLength)
. Una desventaja es Count () enumera la lista.Ok, arrojaré mi sombrero al ring. Las ventajas de mi algoritmo:
El código:
Como se señala en los comentarios a continuación, este enfoque en realidad no aborda la pregunta original que pedía un número fijo de secciones de aproximadamente la misma longitud. Dicho esto, aún puede usar mi enfoque para resolver la pregunta original llamándolo de esta manera:
Cuando se usa de esta manera, el enfoque ya no es O (1) ya que la operación Count () es O (N).
fuente
Esto es lo mismo que la respuesta aceptada, pero una representación mucho más simple:
El método anterior divide una
IEnumerable<T>
N en un número de trozos de igual tamaño o casi iguales.El método anterior divide un
IEnumerable<T>
trozo en trozos del tamaño fijo deseado y el número total de trozos no es importante, de lo que no se trata la pregunta.El problema con el
Split
método, además de ser más lento, es que codifica la salida en el sentido de que la agrupación se realizará sobre la base de un múltiplo de N para cada posición, o en otras palabras, no obtendrá los fragmentos En el orden original.Casi todas las respuestas aquí no conservan el orden, o se trata de particionar y no dividir, o simplemente es incorrecto. Pruebe esto, que es más rápido, conserva el orden pero un poco más detallado:
El método equivalente para una
Partition
operación aquífuente
He estado usando la función Partición que publiqué anteriormente con bastante frecuencia. Lo único malo fue que no se transmitía por completo. Esto no es un problema si trabaja con pocos elementos en su secuencia. Necesitaba una nueva solución cuando comencé a trabajar con más de 100.000 elementos en mi secuencia.
La siguiente solución es mucho más compleja (¡y más código!), Pero es muy eficiente.
¡Disfrutar!
fuente
Hilo interesante. Para obtener una versión de transmisión de Split / Partition, uno puede usar enumeradores y producir secuencias del enumerador utilizando métodos de extensión. La conversión de código imperativo a código funcional usando el rendimiento es una técnica muy poderosa.
Primero, una extensión de enumerador que convierte una cuenta de elementos en una secuencia perezosa:
Y luego una extensión enumerable que divide una secuencia:
El resultado final es una implementación altamente eficiente, de transmisión y perezosa que se basa en un código muy simple.
¡Disfrutar!
fuente
Yo uso esto:
fuente
Esto es eficiente en memoria y difiere la ejecución tanto como sea posible (por lote) y opera en tiempo lineal O (n)
fuente
Hay muchas respuestas geniales para esta pregunta (y sus primos). Lo necesitaba yo mismo y había creado una solución diseñada para ser eficiente y tolerante a errores en un escenario donde la colección de origen puede tratarse como una lista. No utiliza ninguna iteración perezosa, por lo que puede no ser adecuado para colecciones de tamaño desconocido que pueden aplicar presión de memoria.
He visto algunas respuestas en esta familia de preguntas que usan GetRange y Math.Min. Pero creo que, en general, esta es una solución más completa en términos de verificación de errores y eficiencia.
fuente
fuente
Grandes respuestas, para mi escenario probé la respuesta aceptada, y parece que no mantiene el orden. También hay una gran respuesta de Nawfal que mantiene el orden. Pero en mi caso, quería dividir el resto de una manera normalizada, todas las respuestas que vi difundieron el resto o al principio o al final.
Mi respuesta también toma que el resto se extienda de manera más normalizada.
fuente
Si el orden en estas partes no es muy importante, puede intentar esto:
Sin embargo, estos no se pueden transmitir a IEnumerable <IEnumerable <int>> por alguna razón ...
fuente
Este es mi código, bonito y corto.
fuente
Este es mi camino, enumerando artículos y dividiendo filas por columnas
fuente
Estaba buscando una división como la que tiene cadena, por lo que toda la Lista se divide de acuerdo con alguna regla, no solo la primera parte, esta es mi solución
fuente
Aquí hay un pequeño ajuste para la cantidad de elementos en lugar de la cantidad de partes:
fuente
fuente
Acabo de encontrar este hilo, y la mayoría de las soluciones aquí implican agregar elementos a las colecciones, materializando efectivamente cada página antes de devolverla. Esto es malo por dos razones: en primer lugar, si sus páginas son grandes, hay una sobrecarga de memoria para llenar la página, en segundo lugar, hay iteradores que invalidan los registros anteriores cuando avanza al siguiente (por ejemplo, si ajusta un DataReader dentro de un método de enumerador) .
Esta solución utiliza dos métodos de enumerador anidados para evitar la necesidad de almacenar en caché los elementos en colecciones temporales. Dado que los iteradores externo e interno atraviesan el mismo enumerable, necesariamente comparten el mismo enumerador, por lo que es importante no avanzar el externo hasta que haya terminado de procesar la página actual. Dicho esto, si decide no iterar por toda la página actual, cuando pase a la página siguiente, esta solución iterará hacia adelante hasta el límite de la página automáticamente.
fuente