Suskirstykite sąrašą į sublistus naudojant LINQ

Ar yra būdas atskirti „ List<SomeObject> iš kelių atskirų sąrašų „ SomeObject , naudojant elemento indeksą kaip kiekvieno atskyrimo separatorių?

Aš duosiu pavyzdį:

Turiu List<SomeObject> , ir man reikia List<List<SomeObject>> arba List<SomeObject>[] , todėl kiekviename iš šių sąrašų bus 3 elementų sąrašo grupė (nuosekliai).

pavyzdžiui:

  • Šaltinis: [a, g, e, w, p, s, q, f, x, y, i, m, c]

  • Rezultatų sąrašai: [a, g, e], [w, p, s], [q, f, x], [y, i, m], [c]

Man reikia, kad gautas sąrašas būtų šios funkcijos parametras.

308
07 янв. Felipe Lima yra nustatytas 07 sausis 2009-01-07 05:43 '09, 5:43 val. 2009-01-07 05:43
@ 23 atsakymai

Pabandykite naudoti šį kodą.

 public static IList<IList<T>> Split<T>(IList<T> source) { return source .Select((x, i) => new { Index = i, Value = x }) .GroupBy(x => x.Index / 3) .Select(x => x.Select(v => v.Value).ToList()) .ToList(); } 

Idėja yra pirmiausia grupuoti elementus pagal indeksą. Paskirstymas į tris grupes suskirstomas į 3 grupes. Tada kiekviena grupė konvertuojama į sąrašą ir iš List į List įtraukiamas IEnumerable ListList s

306
07 янв. Atsakymą pateikė JaredPar sausio 7 d 2009-01-07 06:05 '09, 06:05 am. 2009-01-07 06:05

Šis klausimas yra šiek tiek pasenęs, bet aš jį parašiau, ir manau, kad tai šiek tiek elegantiškesnė nei kiti siūlomi sprendimai:

 /// <summary> /// Break a list of items into chunks of a specific size /// </summary> public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize) { while (source.Any()) { yield return source.Take(chunksize); source = source.Skip(chunksize); } } 
280
15 июня '11 в 21:40 2011-06-15 21:40 CaseyB atsakymas birželio 15 d. 11 val. 21.40.2011-06-15 21:40

Apskritai, CaseyB pasiūlytas požiūris puikiai veikia, iš tiesų, jei einate į List<T> , sunku kaltinti, galbūt norėčiau pakeisti jį į:

 public static IEnumerable<IEnumerable<T>> ChunkTrivialBetter<T>(this IEnumerable<T> source, int chunksize) { var pos = 0; while (source.Skip(pos).Any()) { yield return source.Skip(pos).Take(chunksize); pos += chunksize; } } 

Tai padės išvengti didelių skambučių grandinių. Tačiau šis metodas turi bendrą trūkumą. Jis išryškina du skaičiavimus vienai daliai, kad išryškintų problemą:

 foreach (var item in Enumerable.Range(1, int.MaxValue).Chunk(8).Skip(100000).First()) { Console.WriteLine(item); } // wait forever 

Norėdami tai išspręsti, mes galime išbandyti Cameron metodą , kuris perkelia pirmiau minėtą testą plaukiojančiose spalvose, nes jis vyksta tik kartą.

Problema yra ta, kad ji turi dar vieną trūkumą, jis materializuoja kiekvieną elementą kiekviename fragmente, problema yra ta, kad dirbate aukštai atmintyje.

Norėdami parodyti, ką bandyti paleisti:

 foreach (var item in Enumerable.Range(1, int.MaxValue) .Select(x => x + new string('x', 100000)) .Clump(10000).Skip(100).First()) { Console.Write('.'); } // OutOfMemoryException 

Galiausiai, bet koks įgyvendinimas turėtų turėti galimybę apdoroti gabalų iteraciją, pavyzdžiui:

 Enumerable.Range(1,3).Chunk(2).Reverse.ToArray() // should return [3],[1,2] 

Daugelis labai optimalių sprendimų, tokių kaip mano pirmasis šio atsakymo persvarstymas , nepavyko. Tą pačią problemą galima rasti optimizuotame atsakyme casperOne .

Jei norite išspręsti visas šias problemas, galite naudoti šiuos veiksmus:

 namespace ChunkedEnumerator { public static class Extensions { class ChunkedEnumerable<T> : IEnumerable<T> { class ChildEnumerator : IEnumerator<T> { ChunkedEnumerable<T> parent; int position; bool done = false; T current; public ChildEnumerator(ChunkedEnumerable<T> parent) { this.parent = parent; position = -1; parent.wrapper.AddRef(); } public T Current { get { if (position == -1 || done) { throw new InvalidOperationException(); } return current; } } public void Dispose() { if (!done) { done = true; parent.wrapper.RemoveRef(); } } object System.Collections.IEnumerator.Current { get { return Current; } } public bool MoveNext() { position++; if (position + 1 > parent.chunkSize) { done = true; } if (!done) { done = !parent.wrapper.Get(position + parent.start, out current); } return !done; } public void Reset() { // per http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset.aspx throw new NotSupportedException(); } } EnumeratorWrapper<T> wrapper; int chunkSize; int start; public ChunkedEnumerable(EnumeratorWrapper<T> wrapper, int chunkSize, int start) { this.wrapper = wrapper; this.chunkSize = chunkSize; this.start = start; } public IEnumerator<T> GetEnumerator() { return new ChildEnumerator(this); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } class EnumeratorWrapper<T> { public EnumeratorWrapper (IEnumerable<T> source) { SourceEumerable = source; } IEnumerable<T> SourceEumerable {get; set;} Enumeration currentEnumeration; class Enumeration { public IEnumerator<T> Source { get; set; } public int Position { get; set; } public bool AtEnd { get; set; } } public bool Get(int pos, out T item) { if (currentEnumeration != null  currentEnumeration.Position > pos) { currentEnumeration.Source.Dispose(); currentEnumeration = null; } if (currentEnumeration == null) { currentEnumeration = new Enumeration { Position = -1, Source = SourceEumerable.GetEnumerator(), AtEnd = false }; } item = default(T); if (currentEnumeration.AtEnd) { return false; } while(currentEnumeration.Position < pos) { currentEnumeration.AtEnd = !currentEnumeration.Source.MoveNext(); currentEnumeration.Position++; if (currentEnumeration.AtEnd) { return false; } } item = currentEnumeration.Source.Current; return true; } int refs = 0; // needed for dispose semantics public void AddRef() { refs++; } public void RemoveRef() { refs--; if (refs == 0  currentEnumeration != null) { var copy = currentEnumeration; currentEnumeration = null; copy.Source.Dispose(); } } } public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize) { if (chunksize < 1) throw new InvalidOperationException(); var wrapper = new EnumeratorWrapper<T>(source); int currentPos = 0; T ignore; try { wrapper.AddRef(); while (wrapper.Get(currentPos, out ignore)) { yield return new ChunkedEnumerable<T>(wrapper, chunksize, currentPos); currentPos += chunksize; } } finally { wrapper.RemoveRef(); } } } class Program { static void Main(string[] args) { int i = 10; foreach (var group in Enumerable.Range(1, int.MaxValue).Skip(10000000).Chunk(3)) { foreach (var n in group) { Console.Write(n); Console.Write(" "); } Console.WriteLine(); if (i-- == 0) break; } var stuffs = Enumerable.Range(1, 10).Chunk(2).ToArray(); foreach (var idx in new [] {3,2,1}) { Console.Write("idx " + idx + " "); foreach (var n in stuffs[idx]) { Console.Write(n); Console.Write(" "); } Console.WriteLine(); }  Console.ReadKey(); } } } 

Taip pat yra optimizavimo raundas, kurį galite įvesti iteracijai be užsakymo, kuris čia nepatenka.

Kaip turėtumėte pasirinkti? Tai visiškai priklauso nuo problemos, kurią bandote išspręsti. Jei nesate suinteresuotas pirmuoju trūkumu, paprastas atsakymas yra neįtikėtinai patrauklus.

Atkreipkite dėmesį , kad, kaip ir daugeliu būdų, tai daugeliui sričių nėra saugi, medžiaga gali tapti keista, jei norite, kad ji būtų saugi, reikia pakeisti „ EnumeratorWrapper .

88
03 мая '12 в 8:15 2012-05-03 08:15 atsakymą davė Sam Saffron 03 gegužės 12 d. 8:15 2012-05-03 08:15

Galite naudoti kelias užklausas, kuriose naudojamas „ Take and Skip , tačiau tai, manau, pridės per daug iteracijų į pradinį sąrašą.

Manau, kad turėtumėte sukurti savo iteratorių, pavyzdžiui:

 public static IEnumerable<IEnumerable<T>> GetEnumerableOfEnumerables<T>( IEnumerable<T> enumerable, int groupSize) { // The list to return. List<T> list = new List<T>(groupSize); // Cycle through all of the items. foreach (T item in enumerable) { // Add the item. list.Add(item); // If the list has the number of elements, return that. if (list.Count == groupSize) { // Return the list. yield return list; // Set the list to a new list. list = new List<T>(groupSize); } } // Return the remainder if there is any, if (list.Count != 0) { // Return the list. yield return list; } } 

Tada galite skambinti ir įgalinti LINQ, kad galėtumėte atlikti kitas operacijas su gautomis sekomis.


Atsižvelgiant į Samo atsakymą , manau, kad tai lengviau, be:

  • Pakartotinai per sąrašą (kurį aš iš pradžių nedariau)
  • Elementų materializavimas grupėse prieš kūrinio išleidimą (dideliems elementų fragmentams bus atminties problemų)
  • Visi kodai Sam išsiųsti

Taigi čia dar vienas leidimas, IEnumerable<T> pratęsimo metode, vadinamame Chunk :

 public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunkSize) { // Validate parameters. if (source == null) throw new ArgumentNullException("source"); if (chunkSize <= 0) throw new ArgumentOutOfRangeException("chunkSize", "The chunkSize parameter must be a positive value."); // Call the internal implementation. return source.ChunkInternal(chunkSize); } 

Nenuostabu, tik klaidų tikrinimas.

Perjungti į „ ChunkInternal :

 private static IEnumerable<IEnumerable<T>> ChunkInternal<T>( this IEnumerable<T> source, int chunkSize) { // Validate parameters. Debug.Assert(source != null); Debug.Assert(chunkSize > 0); // Get the enumerator. Dispose of when done. using (IEnumerator<T> enumerator = source.GetEnumerator()) do { // Move to the next element. If there nothing left // then get out. if (!enumerator.MoveNext()) yield break; // Return the chunked sequence. yield return ChunkSequence(enumerator, chunkSize); } while (true); } 

Iš esmės ji gauna „ IEnumerator<T> ir rankiniu būdu pakartoja kiekvieną elementą. Ji patikrina, ar yra kokių nors šiuo metu išvardytų elementų. Po kiekvieno fragmentų sąrašų, jei nėra elementų, jie ištraukiami.

Kai tik jis sužino, kad yra sekos elementų, jis perduoda atsakomybę už „ IEnumerable<T> vidinį diegimą„ ChunkSequence :

 private static IEnumerable<T> ChunkSequence<T>(IEnumerator<T> enumerator, int chunkSize) { // Validate parameters. Debug.Assert(enumerator != null); Debug.Assert(chunkSize > 0); // The count. int count = 0; // There is at least one item. Yield and then continue. do { // Yield the item. yield return enumerator.Current; } while (++count < chunkSize  enumerator.MoveNext()); } 

Kadangi „ MoveNext jau MoveNext pakviestas į „ IEnumerator<T> perduodamas „ ChunkSequence , jis grąžina „ Current grąžinamą elementą, o paskui chunkSize skaitiklį, kad niekada negrąžintų daugiau „ chunkSize elementų ir chunkSize prie kito elemento sekoje po kiekvieno iteracijos (bet trumpasis jungimas, jei numeris yra elementai viršija gabalo dydį).

Jei nėra elementų, „ InternalChunk metodas padarys kitą leidimą išorinėje kilpoje, bet kai „ MoveNext yra vadinamas antrą kartą, jis vis tiek grąžins klaidingą informaciją pagal dokumentaciją (paryškintą mano):

Jei „MoveNext“ perduoda kolekcijos pabaigą, skaičiuoklė yra po paskutinio kolekcijos elemento ir MoveNext grąžina klaidingą. Kai skaitytojas yra šioje padėtyje, paskesni „MoveNext“ skambučiai taip pat grįžta į false, kol bus iškviestas „Reset“.

Šiuo metu ciklas nutraukiamas ir sekų seka bus baigta.

Tai paprastas testas:

 static void Main() { string s = "agewpsqfxyimc"; int count = 0; // Group by three. foreach (IEnumerable<char> g in s.Chunk(3)) { // Print out the group. Console.Write("Group: {0} - ", ++count); // Print the items. foreach (char c in g) { // Print the item. Console.Write(c + ", "); } // Finish the line. Console.WriteLine(); } } 

Išvada:

 Group: 1 - a, g, e, Group: 2 - w, p, s, Group: 3 - q, f, x, Group: 4 - y, i, m, Group: 5 - c, 

Svarbi pastaba: tai neveikia, jei neišeikvojate visos vaiko sekos arba jos nepažeidžiate nė viename iš tėvų sekos taškų. Tai yra labai atsargus, bet jei jūsų naudojimo atvejis yra tas, kad naudosite kiekvieną sekos sekos elementą, tai bus jums naudinga.

Be to, jis atliks keistus dalykus, jei žaisite su tvarka, lygiai taip pat kaip ir Sam .

59
07 янв. atsakymas, kurį pateikė casperOne Jan 07 2009-01-07 06:02 '09, 6:02 am. 2009-01-07 06:02

Na, čia aš perima:

  • visiškai tingus: dirba su begaliniais pervedimais
  • tarpinis kopijavimas / buferiavimas
  • O (n) vykdymo laikas
  • taip pat veikia, kai vidinės sekos suvartojamos tik iš dalies.

 public static IEnumerable<IEnumerable<T>> Chunks<T>(this IEnumerable<T> enumerable, int chunkSize) { if (chunkSize < 1) throw new ArgumentException("chunkSize must be positive"); using (var e = enumerable.GetEnumerator()) while (e.MoveNext()) { var remaining = chunkSize; // elements remaining in the current chunk var innerMoveNext = new Func<bool>(() => --remaining > 0  e.MoveNext()); yield return e.GetChunk(innerMoveNext); while (innerMoveNext()) {} } } private static IEnumerable<T> GetChunk<T>(this IEnumerator<T> e, Func<bool> innerMoveNext) { do yield return e.Current; while (innerMoveNext()); } 

Naudojimo pavyzdys

 var src = new [] {1, 2, 3, 4, 5, 6}; var c3 = src.Chunks(3); // {{1, 2, 3}, {4, 5, 6}}; var c4 = src.Chunks(4); // {{1, 2, 3, 4}, {5, 6}}; var sum = c3.Select(c => c.Sum()); // {6, 15} var count = c3.Count(); // 2 var take2 = c3.Select(c => c.Take(2)); // {{1, 2}, {4, 5}} 

Paaiškinimai

Kodas veikia įterpiant du yield pagrįstus iteratorius.

Išorinis iteratorius turi stebėti, kiek elementų efektyviai naudojo vidinis (gabalas) iteratorius. Tai daroma uždarant remaining su „ innerMoveNext() . Nepanaudoti gabaliukai pašalinami prieš tai, kai išorinis iteratorius gauna kitą gabalą. Tai būtina, nes kitaip gausite nenuoseklius rezultatus, kai vidiniai skaičiuojami elementai nebus (visiškai) suvartoti (pvz., c3.Count() grąžina 6).

Pastaba . Atsakymas buvo atnaujintas, siekiant ištaisyti @aolszowka pastebėtus trūkumus.

35
06 янв. atsakymą pateikė 3dgrabber 06 sausis 2014-01-06 18:40 '14 at 18:40 2014-01-06 18:40

visiškai tingus, nesuskaičiuojant ar kopijuojant:

 public static class EnumerableExtensions { public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int len) { if (len == 0) throw new ArgumentNullException(); var enumer = source.GetEnumerator(); while (enumer.MoveNext()) { yield return Take(enumer.Current, enumer, len); } } private static IEnumerable<T> Take<T>(T head, IEnumerator<T> tail, int len) { while (true) { yield return head; if (--len == 0) break; if (tail.MoveNext()) head = tail.Current; else break; } } } 
13
23 февр. atsakymą pateikė vartotojo1583558 vasario 23 d. 2015-02-23 22:57 '15, 10:57 pm 2015-02-23 22:57

Manau, kad kitas sakinys bus greičiausias. Aš aukojau šaltinio tingumą, kad galėčiau išvardyti galimybę naudoti Array.Copy ir žinoti iš anksto kiekvieno iš mano sąrašų ilgį.

 public static IEnumerable<T[]> Chunk<T>(this IEnumerable<T> items, int size) { T[] array = items as T[] ?? items.ToArray(); for (int i = 0; i < array.Length; i+=size) { T[] chunk = new T[Math.Min(size, array.Length - i)]; Array.Copy(array, i, chunk, 0, chunk.Length); yield return chunk; } } 
12
20 сент. Atsakymą pateikė Marc-André Bertrand 20 rugsėjis. 2014-09-20 00:03 '14 - 0:03 2014-09-20 00:03

Mes galime patobulinti @JaredPar sprendimą, kad būtų atliktas tikras tingus vertinimas. Mes naudojame „ GroupAdjacentBy metodą, kuris iš eilės elementų grupėms suteikia tą patį raktą:

 sequence .Select((x, i) => new { Value = x, Index = i }) .GroupAdjacentBy(x=>x.Index/3) .Select(g=>g.Select(x=>x.Value)) 

Kadangi grupės gaunamos vienas po kito, šis sprendimas efektyviai veikia su ilgomis arba begalinėmis sekomis.

8
12 июля '12 в 1:59 2012-07-12 01:59 atsakymą pateikė pulkininkas Panikas liepos 12 d., 12 val

„System.Interactive “ šiam tikslui suteikia Buffer() . Kai kurie greiti testai rodo, kad našumas yra panašus į Sam sprendimą.

8
03 мая '12 в 9:24 2012-05-03 09:24 atsakymas pateikiamas dahlbyk 03 gegužės 12 d. 9:24 2012-05-03 09:24

Štai sąrašas, suskirstymo procedūra, kurią parašiau prieš porą mėnesių:

 public static List<List<T>> Chunk<T>( List<T> theList, int chunkSize ) { List<List<T>> result = theList .Select((x, i) => new { data = x, indexgroup = i / chunkSize }) .GroupBy(x => x.indexgroup, x => x.data) .Select(g => new List<T>(g)) .ToList(); return result; } 
6
07 янв. Atsakymą pateikė David B 07 jan. 2009-01-07 17:41 '09, 17:41 val. 2009-01-07 17:41

Tai senas klausimas, bet tai, ką aš susidūriau; jis įtraukia sąrašą tik vieną kartą, tačiau kiekvienam skyriui sukuria sąrašus. Tai nepatiria netikėto elgesio, kai „ ToArray() yra vadinama kai kuriais įgyvendinimais:

  public static IEnumerable<IEnumerable<T>> Partition<T>(IEnumerable<T> source, int chunkSize) { if (source == null) { throw new ArgumentNullException("source"); } if (chunkSize < 1) { throw new ArgumentException("Invalid chunkSize: " + chunkSize); } using (IEnumerator<T> sourceEnumerator = source.GetEnumerator()) { IList<T> currentChunk = new List<T>(); while (sourceEnumerator.MoveNext()) { currentChunk.Add(sourceEnumerator.Current); if (currentChunk.Count == chunkSize) { yield return currentChunk; currentChunk = new List<T>(); } } if (currentChunk.Any()) { yield return currentChunk; } } } 
5
13 мая '14 в 16:56 2014-05-13 16:56 atsakymas pateikiamas aolszowka gegužės 13 d. 14, 16:56 2014-05-13 16:56

Manau, kad šis nedidelis gabalas labai gerai atlieka darbą.

 public static IEnumerable<List<T>> Chunked<T>(this List<T> source, int chunkSize) { var offset = 0; while (offset < source.Count) { yield return source.GetRange(offset, Math.Min(source.Count - offset, chunkSize)); offset += chunkSize; } } 
5
01 апр. atsakymas duotas erlando 01 Bal 2015-04-01 23:18 '15, 23:18, 2015-04-01 23:18

Prieš keletą metų parašiau „Clump“ pratęsimo metodą. Veikia puikiai ir yra greičiausias įgyvendinimas čia: P

 /// <summary> /// Clumps items into same size lots. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source">The source list of items.</param> /// <param name="size">The maximum size of the clumps to make.</param> /// <returns>A list of list of items, where each list of items is no bigger than the size given.</returns> public static IEnumerable<IEnumerable<T>> Clump<T>(this IEnumerable<T> source, int size) { if (source == null) throw new ArgumentNullException("source"); if (size < 1) throw new ArgumentOutOfRangeException("size", "size must be greater than 0"); return ClumpIterator<T>(source, size); } private static IEnumerable<IEnumerable<T>> ClumpIterator<T>(IEnumerable<T> source, int size) { Debug.Assert(source != null, "source is null."); T[] items = new T[size]; int count = 0; foreach (var item in source) { items[count] = item; count++; if (count == size) { yield return items; items = new T[size]; count = 0; } } if (count > 0) { if (count == size) yield return items; else { T[] tempItems = new T[count]; Array.Copy(items, tempItems, count); yield return tempItems; } } } 
5
03 мая '12 в 9:42 2012-05-03 09:42 atsakymą pateikė Cameron MacFarland gegužės 03 d. 12 val. 9:42 2012-05-03 09:42

Šis kitas sprendimas yra kompaktiškiausias, kurį galėčiau galvoti, tai yra O (n).

 public static IEnumerable<T[]> Chunk<T>(IEnumerable<T> source, int chunksize) { var list = source as IList<T> ?? source.ToList(); for (int start = 0; start < list.Count; start += chunksize) { T[] chunk = new T[Math.Min(chunksize, list.Count - start)]; for (int i = 0; i < chunk.Length; i++) chunk[i] = list[start + i]; yield return chunk; } } 
4
13 дек. Atsakymą pateikė Marc-André Bertrand gruodžio 13 d. 2014-12-13 00:21 '14 - 0:21 2014-12-13 00:21

Senasis kodas, bet tai ir aš:

  public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max) { 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()) { yield return toReturn; } } 
4
25 февр. Robert McKee atsakymas, pateiktas vasario 25 d 2015-02-25 12:31 '15, 12:31 pm 2015-02-25 12:31

Jei sąrašas yra system.collections.generic, galite naudoti „CopyTo“ metodą, kad kopijuotumėte savo masyvo elementus į kitas submatrices. Jūs nurodote pradinį elementą ir nukopijuotų elementų skaičių.

Savo pradiniame sąraše taip pat galite sudaryti 3 klonus ir kiekviename sąraše naudoti „RemoveRange“, kad sąrašas būtų sumažintas iki norimo dydžio.

Arba tiesiog sukurkite pagalbininko metodą tai padaryti.

3
07 янв. atsakymas suteiktas Jobo 07 jan. 2009-01-07 05:51 '09, 5:51 val. 2009-01-07 05:51

Raskime sprendimą David B geriausiai. Tačiau mes pritaikėme jį prie labiau bendro sprendimo:

 list.GroupBy(item => item.SomeProperty) .Select(group => new List<T>(group)) .ToArray(); 
3
09 апр. Atsakymą pateikė mwjackson 09 Bal 2010-04-09 13:28 '10, 13:28, 2010-04-09 13:28

Kaip apie tai?

 var input = new List<string> { "a", "g", "e", "w", "p", "s", "q", "f", "x", "y", "i", "m", "c" }; var k = 3 var res = Enumerable.Range(0, (input.Count - 1) / k + 1) .Select(i => input.GetRange(i * k, Math.Min(k, input.Count - i * k))) .ToList(); 

Kiek aš žinau, GetRange () yra linijinis priimamų vienetų skaičiumi. Todėl ji turėtų veikti gerai.

3
13 авг. Atsakymas duotas Roman Pekar 13 rug. 2013-08-13 11:45 '13, 11:45 2013-08-13 11:45

Naudojant modulinį skaidymą:

 public IEnumerable<IEnumerable<string>> Split(IEnumerable<string> input, int chunkSize) { var chunks = (int)Math.Ceiling((double)input.Count() / (double)chunkSize); return Enumerable.Range(0, chunks).Select(id => input.Where(s => s.GetHashCode() % chunks == id)); } 
1
15 авг. Janosz G. atsakymas 15 rug . 2012-08-15 21:38 '12, 09:38 PM 2012-08-15 21:38

Tai senas sprendimas, tačiau aš turėjau kitokį požiūrį. Aš naudoju „ Skip kad pereitumėte į norimą nuokrypį, ir „ Take norite išgauti norimą elementų skaičių:

 public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunkSize) { if (chunkSize <= 0) throw new ArgumentOutOfRangeException($"{nameof(chunkSize)} should be > 0"); var nbChunks = (int)Math.Ceiling((double)source.Count()/chunkSize); return Enumerable.Range(0, nbChunks) .Select(chunkNb => source.Skip(chunkNb*chunkSize) .Take(chunkSize)); } 
1
27 окт. Bertrando spalio 27 d. atsakymas 2016-10-27 09:31 '16 at 9:31 am 2016-10-27 09:31

Tiesiog įdėkite mano du centus. Jei norite sąrašo „kibirą“ (vizualizuoti iš kairės į dešinę), galite atlikti šiuos veiksmus:

  public static List<List<T>> Buckets<T>(this List<T> source, int numberOfBuckets) { List<List<T>> result = new List<List<T>>(); for (int i = 0; i < numberOfBuckets; i++) { result.Add(new List<T>()); } int count = 0; while (count < source.Count()) { var mod = count % numberOfBuckets; result[mod].Add(source[count]); count++; } return result; } 
1
30 авг. atsakymą pateikė user1883961 30 rug . 2017-08-30 18:27 '17, 18:27 pm 2017-08-30 18:27

Aš paėmiau pagrindinį atsakymą ir padariau jį kaip TOK konteinerį, kad išsiaiškintume, kur suskaidyti. (Tiems, kurie tikrai ieško tik padalijimo į 3 elementus, skaitant šį pranešimą ieškant atsakymo?)

Šis metodas leidžia jums suskirstyti į bet kokio tipo elementus.

 public static List<List<T>> SplitOn<T>(List<T> main, Func<T, bool> splitOn) { int groupIndex = 0; return main.Select( item => new { Group = (splitOn.Invoke(item) ? ++groupIndex : groupIndex), Value = item }) .GroupBy( it2 => it2.Group) .Select(x => x.Select(v => v.Value).ToList()) .ToList(); } 

Taigi, OP kodas bus

 var it = new List<string>() { "a", "g", "e", "w", "p", "s", "q", "f", "x", "y", "i", "m", "c" }; int index = 0; var result = SplitOn(it, (itm) => (index++ % 3) == 0 ); 
0
06 сент. Atsakymą pateikė „ OmegaMan“ 06.09. 2017-09-06 19:09 '17, 7:09 pm 2017-09-06 19:09

Įterpti du centus ...

Naudojant sąrašo tipą, kad šaltinis būtų sugadintas, radau kitą labai kompaktišką sprendimą:

 public static IEnumerable<IEnumerable<TSource>> Chunk<TSource>(this IEnumerable<TSource> source, int chunkSize) { // copy the source into a list var chunkList = source.ToList(); // return chunks of 'chunkSize' items while (chunkList.Count > chunkSize) { yield return chunkList.GetRange(0, chunkSize); chunkList.RemoveRange(0, chunkSize); } // return the rest yield return chunkList; } 
-1
13 янв. Atsakymas pateikiamas Patrick January 13 2015-01-13 12:55 '15 at 12:55 2015-01-13 12:55

Kiti klausimai dėl žymių arba Užduoti klausimą