digitalmars.D.learn - Getting equivalent elements in a range/array
- Andrej M. (10/10) May 07 2011 I want to turn this:
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (42/52) May 07 2011 This seems to work, but needs more work. :)
- Andrej Mitrovic (51/51) May 07 2011 Fantastic work, thanks! I'll look into more detail tomorrow, but it
- bearophile (8/15) May 08 2011 Currently if you use group like this:
- Andrej Mitrovic (1/1) May 08 2011 Thanks, group seems to work fine too.
I want to turn this: auto arr = [1, 1, 2, 3, 4, 4]; into this: auto arr2 = [[1, 1], [2], [3], [4, 4]]; I want an array of arrays of the same elements. Lazy or not, I don't care. I thought I could get away with this inside some while loop: auto equals = array(filter!"a == b"(arr)); arr = arr[equals.length-1..$]; Nope. I need this for some buffered output, where the requirement is the elements of the buffer all need to have the same properties so a function can output a buffer of elements in one call instead of calling the function for each element (the function call is expensive).
May 07 2011
On 05/07/2011 09:07 PM, Andrej M. wrote:I want to turn this: auto arr = [1, 1, 2, 3, 4, 4]; into this: auto arr2 = [[1, 1], [2], [3], [4, 4]]; I want an array of arrays of the same elements. Lazy or not, I don't care. I thought I could get away with this inside some while loop: auto equals = array(filter!"a == b"(arr)); arr = arr[equals.length-1..$]; Nope. I need this for some buffered output, where the requirement is the elements of the buffer all need to have the same properties so a function can output a buffer of elements in one call instead of calling the function for each element (the function call is expensive).This seems to work, but needs more work. :) import std.stdio; import std.array; struct EquivalentElements { int[] range; int[] front_; this(int[] range) { this.range = range; this.front_ = popEqualFront(this.range); } bool empty() { return front_.empty; } int[] front() { return front_; } void popFront() { this.front_ = popEqualFront(this.range); } private int[] popEqualFront(ref int[] range) { int[] front; if (!range.empty) { do { front ~= range[0]; range = range[1..$]; } while (!range.empty && (front[$-1] == range[0])); } return front; } } void main() { writeln(EquivalentElements([1, 1, 2, 3, 4, 4])); }
May 07 2011
Fantastic work, thanks! I'll look into more detail tomorrow, but it looks good so far. Just added a function helper and made the struct typed: import std.array; import std.range; struct EquivalentElements(T) { T range; T front_; this(T range) { this.range = range; this.front_ = popEqualFront(this.range); } bool empty() { return front_.empty; } T front() { return front_; } void popFront() { this.front_ = popEqualFront(this.range); } private T popEqualFront(ref T range) { T front; if (!range.empty) { do { front ~= range[0]; range = range[1..$]; } while (!range.empty && (front[$-1] == range[0])); } return front; } } EquivalentElements!(Range) equivalentElements(Range)(Range r) { return typeof(return)(r); } // test void main() { foreach (elem; equivalentElements([1, 1, 2, 3, 4, 4])) { writeln(elem); } }
May 07 2011
Andrej M.:I want to turn this: auto arr = [1, 1, 2, 3, 4, 4]; into this: auto arr2 = [[1, 1], [2], [3], [4, 4]]; I want an array of arrays of the same elements. Lazy or not, I don't care.Currently if you use group like this: writeln(arr.group()); You get: [Tuple!(int,uint)(1, 2), Tuple!(int,uint)(2, 1), Tuple!(int,uint)(3, 1), Tuple!(int,uint)(4, 2)] Andrei has recently said he wants to modify group() to make it work more like python itertools.groupby(), so it will do what you want (the duplicated items too will be lazy, as in Python). Bye, bearophile
May 08 2011
Thanks, group seems to work fine too.
May 08 2011