Existe-t-il un bon moyen de diviser une collection en plusieurs n
parties avec LINQ? Pas nécessairement uniformément bien sûr.
Autrement dit, je veux diviser la collection en sous-collections, qui contiennent chacune un sous-ensemble d'éléments, où la dernière collection peut être déchiquetée.
c#
.net
linq
data-structures
Simon_Weaver
la source
la source
Réponses:
Un linq pur et la solution la plus simple est comme indiqué ci-dessous.
la source
.AsEnumerable()
n'est pas nécessaire, IGrouping <T> est déjà un IEnumerable <T>.EDIT: D'accord, il semble que j'ai mal lu la question. Je l'ai lu comme "morceaux de longueur n" plutôt que "n morceaux". Doh! Envisager de supprimer la réponse ...
(Réponse originale)
Je ne pense pas qu'il existe une méthode intégrée de partitionnement, même si j'ai l'intention d'en écrire une dans mon ensemble d'ajouts à LINQ to Objects. Marc Gravell a une implémentation ici même si je la modifierais probablement pour renvoyer une vue en lecture seule:
la source
yield return
. Il faut qu'un seul lot soit en mémoire à la fois, mais c'est tout.la source
var dept = {1,2,3,4,5}
. Après avoir divisé le résultat, c'est commedept1 = {1,3,5}
etdept2 = { 2,4 }
oùparts = 2
. Mais le résultat dont j'ai besoin estdept1 = {1,2,3}
etdept2 = {4,5}
int columnLength = (int)Math.Ceiling((decimal)(list.Count()) / parts);
puis fait la division avec.GroupBy(x => x.index / columnLength)
. Un inconvénient est que Count () énumère la liste.Ok, je vais jeter mon chapeau dans le ring. Les avantages de mon algorithme:
Le code:
Comme indiqué dans les commentaires ci-dessous, cette approche ne répond pas réellement à la question initiale qui demandait un nombre fixe de sections de longueur approximativement égale. Cela dit, vous pouvez toujours utiliser mon approche pour résoudre la question d'origine en l'appelant de cette façon:
Lorsqu'elle est utilisée de cette manière, l'approche n'est plus O (1) car l'opération Count () est O (N).
la source
C'est la même chose que la réponse acceptée, mais une représentation beaucoup plus simple:
La méthode ci-dessus divise un
IEnumerable<T>
nombre N de blocs de tailles égales ou proches de tailles égales.La méthode ci-dessus divise un
IEnumerable<T>
en morceaux de taille fixe souhaitée, le nombre total de morceaux étant sans importance - ce qui n'est pas le sujet de la question.Le problème avec la
Split
méthode, en plus d'être plus lente, est qu'elle brouille la sortie dans le sens où le regroupement se fera sur la base du i'ième multiple de N pour chaque position, ou en d'autres termes, vous n'obtenez pas les morceaux dans l'ordre d'origine.Presque chaque réponse ici ne préserve pas l'ordre, ou concerne le partitionnement et non le fractionnement, ou est tout simplement erronée. Essayez ceci qui est plus rapide, préserve l'ordre mais un peu plus verbeux:
La méthode équivalente pour une
Partition
opération icila source
J'utilise assez souvent la fonction Partition que j'ai postée plus tôt. Le seul inconvénient, c'est que ce n'est pas complètement en streaming. Ce n'est pas un problème si vous travaillez avec peu d'éléments dans votre séquence. J'avais besoin d'une nouvelle solution lorsque j'ai commencé à travailler avec plus de 100 000 éléments dans ma séquence.
La solution suivante est beaucoup plus complexe (et plus de code!), Mais elle est très efficace.
Prendre plaisir!
la source
Fil intéressant. Pour obtenir une version en continu de Split / Partition, on peut utiliser des énumérateurs et produire des séquences de l'énumérateur en utilisant des méthodes d'extension. La conversion du code impératif en code fonctionnel à l'aide de yield est en effet une technique très puissante.
D'abord une extension d'énumérateur qui transforme un nombre d'éléments en une séquence paresseuse:
Et puis une extension énumérable qui partitionne une séquence:
Le résultat final est une implémentation très efficace, en continu et paresseuse qui repose sur un code très simple.
Prendre plaisir!
la source
J'utilise ceci:
la source
Ceci est efficace en mémoire et reporte l'exécution autant que possible (par lot) et fonctionne en temps linéaire O (n)
la source
Il y a beaucoup de bonnes réponses à cette question (et à ses cousins). J'en avais besoin moi-même et j'avais créé une solution conçue pour être efficace et tolérante aux erreurs dans un scénario où la collection source peut être traitée comme une liste. Il n'utilise aucune itération différée et peut donc ne pas convenir aux collections de taille inconnue susceptibles d'appliquer une pression mémoire.
J'ai vu quelques réponses à travers cette famille de questions qui utilisent GetRange et Math.Min. Mais je pense que dans l'ensemble, c'est une solution plus complète en termes de vérification des erreurs et d'efficacité.
la source
la source
Great Answers, pour mon scénario, j'ai testé la réponse acceptée, et il semble qu'elle ne garde pas l'ordre. il y a aussi une excellente réponse de Nawfal qui maintient l'ordre. Mais dans mon scénario, je voulais diviser le reste de manière normalisée, toutes les réponses que j'ai vues se répartissent le reste ou au début ou à la fin.
Ma réponse prend également le reste se répandant de manière plus normalisée.
la source
Si l'ordre dans ces pièces n'est pas très important, vous pouvez essayer ceci:
Cependant, ils ne peuvent pas être convertis en IEnumerable <IEnumerable <int>> pour une raison quelconque ...
la source
Ceci est mon code, joli et court.
la source
C'est ma façon de lister les éléments et de casser ligne par colonne
la source
Je cherchais un split comme celui avec une chaîne, donc toute la liste est divisée selon une règle, pas seulement la première partie, c'est ma solution
la source
Voici un petit ajustement pour le nombre d'éléments au lieu du nombre de pièces:
la source
la source
Je viens de tomber sur ce fil, et la plupart des solutions ici impliquent d'ajouter des éléments aux collections, matérialisant efficacement chaque page avant de la renvoyer. C'est mauvais pour deux raisons: premièrement, si vos pages sont volumineuses, il y a une surcharge de mémoire pour remplir la page, deuxièmement, il y a des itérateurs qui invalident les enregistrements précédents lorsque vous passez au suivant (par exemple si vous enveloppez un DataReader dans une méthode d'énumération) .
Cette solution utilise deux méthodes d'énumérateur imbriquées pour éviter d'avoir à mettre en cache des éléments dans des collections temporaires. Étant donné que les itérateurs externes et internes parcourent le même énumérable, ils partagent nécessairement le même énumérateur, il est donc important de ne pas avancer vers l'extérieur tant que vous n'avez pas terminé le traitement de la page actuelle. Cela dit, si vous décidez de ne pas parcourir complètement la page actuelle, lorsque vous passez à la page suivante, cette solution effectuera automatiquement une itération vers la limite de la page.
la source