.net - Split collection into n of parts is not giving the desired resulting secuences -
i'm trying split collection specific number of parts, i've taken seeying solutions on stackoverflow: split collection `n` parts linq?
this vb.net translation @hasan khan solution:
''' <summary> ''' splits <see cref="ienumerable(of t)"/> specified amount of secuences. ''' </summary> public shared function splitintoparts(of t)(byval col ienumerable(of t), byval amount integer) ienumerable(of ienumerable(of t)) dim integer = 0 dim splits ienumerable(of ienumerable(of t)) = item t in col group item item = threading.interlocked.increment(i) mod amount group select group.asenumerable() return splits end function
and vb.net translation of @manu08 solution:
''' <summary> ''' splits <see cref="ienumerable(of t)"/> specified amount of secuences. ''' </summary> public shared function splitintoparts(of t)(byval col ienumerable(of t), byval amount integer) ienumerable(of ienumerable(of t)) return col.select(function(item, index) new {index, item}). groupby(function(x) x.index mod amount). select(function(x) x.select(function(y) y.item)) end function
the problem both functions returns wrong result.
because if split collection this:
dim maincol ienumerable(of integer) = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} dim splittedcols ienumerable(of ienumerable(of integer)) = splitintoparts(col:=maincol, amount:=2)
both functions gives result:
1: { 1, 3, 5, 7, 9 } 2: { 2, 4, 6, 8, 10 }
instead of these secuences:
1: { 1, 2, 3, 4, 5 } 2: { 6, 7, 8, 9, 10 }
what i'm doing wrong?.
myextensions class has 2 public split methods:
- for icollection - iterates through collection only once - splitting.
- for ienumerable - iterates through enumerable twice: count items , split them. not use if possible (first 1 safe , twice faster).
more of that: algorithm trying bring exactly specified number of collections.
public static class myextensions { // works icollection - iterates through collection once. public static ienumerable<ienumerable<t>> split<t>(this icollection<t> items, int count) { return split(items, items.count, count); } // works ienumerable , iterates items twice: first count items, second split them. public static ienumerable<ienumerable<t>> split<t>(this ienumerable<t> items, int count) { // resharper disable possiblemultipleenumeration var itemscount = items.count(); return split(items, itemscount, count); // resharper restore possiblemultipleenumeration } private static ienumerable<ienumerable<t>> split<t>(this ienumerable<t> items, int itemscount, int partscount) { if (items == null) throw new argumentnullexception("items"); if (partscount <= 0) throw new argumentoutofrangeexception("partscount"); var rem = itemscount % partscount; var min = itemscount / partscount; var max = rem != 0 ? min + 1 : min; var index = 0; var enumerator = items.getenumerator(); while (index < itemscount) { var size = 0 < rem-- ? max : min; yield return splitpart(enumerator, size); index += size; } } private static ienumerable<t> splitpart<t>(ienumerator<t> enumerator, int count) { (var = 0; < count; i++) { if (!enumerator.movenext()) break; yield return enumerator.current; } } }
example program:
var items = new [] {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; for(var = 1; <= items.length + 3; i++) { console.writeline("{0} part(s)", i); foreach (var part in items.split(i)) console.writeline(string.join(", ", part)); console.writeline(); }
... , output of program:
1 part(s) a, b, c, d, e, f, g, h, i, j 2 part(s) a, b, c, d, e f, g, h, i, j 3 part(s) a, b, c, d e, f, g h, i, j 4 part(s) a, b, c d, e, f g, h i, j 5 part(s) a, b c, d e, f g, h i, j 6 part(s) a, b c, d e, f g, h j 7 part(s) a, b c, d e, f g h j 8 part(s) a, b c, d e f g h j 9 part(s) a, b c d e f g h j 10 part(s) b c d e f g h j 11 part(s) // 10 items in collection. b c d e f g h j 12 part(s) // 10 items in collection. b c d e f g h j 13 part(s) // 10 items in collection. b c d e f g h j
Comments
Post a Comment