digitalmars.D.learn - Is there a better way to write this split functionality?
- Andrej Mitrovic (26/26) May 08 2011 import std.stdio;
- bearophile (29/33) May 09 2011 Maybe this does what you want, but it's not very good:
- Andrej Mitrovic (29/29) May 09 2011 Those could be nice solutions, thanks.
import std.stdio; import std.array; import std.range; import std.algorithm; void main() { auto arr = [64, 64, 64, 32, 31, 16, 32, 33, 64]; auto newarr = arr[]; bool state = true; while (arr.length) { newarr = state ? array(until!("a < 32")(arr)) : array(until!("a >= 32")(arr)); arr = arr[newarr.length .. $]; state ^= 1; writeln(newarr); } } The idea is to find as many elements in a sequence that conform to some predicate, followed by as many elements that conform to another predicate. The two predicates are switched on each run. The above code will print: [64, 64, 64, 32] [31, 16] [32, 33, 64] Is there a better way to do this, some std.range/algorithm function I don't know of?
May 08 2011
Andrej Mitrovic:Is there a better way to do this, some std.range/algorithm function I don't know of?Maybe this does what you want, but it's not very good: import std.stdio, std.algorithm; void main() { auto arr = [64, 64, 64, 32, 31, 16, 32, 33, 64]; int last = 0; foreach (g; group!q{ (a < 32) == (b < 32) }(arr)) { writeln(arr[last .. last+g[1]]); last += g[1]; } } With the change to group() Andrei talks about the code becomes a little better (untested code): import std.stdio, std.algorithm; void main() { auto arr = [64, 64, 64, 32, 31, 16, 32, 33, 64]; foreach (g; group!q{ (a < 32) == (b < 32) }(arr)) writeln(g[1]); } In Python groupby uses a key mapping function, like D schwartzSort():[[64, 64, 64, 32], [31, 16], [32, 33, 64]] If group uses a key mapping function as schwartzSort() the code improves (untested): import std.stdio, std.algorithm; void main() { auto arr = [64, 64, 64, 32, 31, 16, 32, 33, 64]; foreach (g; group!q{ a < 32 }(arr)) writeln(g[1]); } Bye, bearophilefrom itertools import groupby arr = [64, 64, 64, 32, 31, 16, 32, 33, 64] [list(g) for h,g in groupby(arr, key = lambda x: x < 32)]
May 09 2011
Those could be nice solutions, thanks. My first code needlessly resizes the original array though. I could simply track the lower index instead: void main() { dchar[] arr = [64, 64, 64, 32, 31, 16, 32, 33, 64]; dchar[] newarr; size_t index; bool state = true; while (index < arr.length) { newarr = state ? array(until!("a < 32")(arr[index..$])) : array(until!("a >= 32")(arr[index..$])); index += newarr.length; state ^= 1; writeln(cast(int[])newarr); } } You know what sucks? I can't assign a range with different predicates to the same variable. E.g. this won't compile: auto newarr = state ? (until!("a < 32")(arr[index..$])) : (until!("a >= 32")(arr[index..$])); Error: incompatible types for ((until(arr[index..__dollar],cast(OpenRight)1)) ? (until(arr[index..__dollar],cast(OpenRight)1))): 'Until!(pred,dchar[],void)' and 'Until!(pred,dchar[],void)' I mean they are basically the same range type, with only a different predicate. Why every template instantiation has to be its own unique type, I'll never understand.
May 09 2011