Comment #0 by bearophile_hugs — 2011-05-15T05:15:06Z
In Python and Haskell there is a way to invert the operation of zip(), this is a commonly used feature/function:
Python (V2.6.6):
>>> s = "abc"
>>> d = [1, 2, 3]
>>> z = zip(s, d)
>>> z
[('a', 1), ('b', 2), ('c', 3)]
>>> zip(*z)
[('a', 'b', 'c'), (1, 2, 3)]
Haskell (GHCI v.7.0.2):
Prelude> let s = "abc"
Prelude> let d = [1, 2, 3]
Prelude> let z = zip s d
Prelude> z
[('a',1),('b',2),('c',3)]
Prelude> unzip z
("abc",[1,2,3])
A D example shows where it's useful:
import std.stdio, std.typecons, std.algorithm, std.range;
Tuple!(int,int) divMod(int n, int m) {
return tuple(n / m, n % m);
}
void main() {
auto r = map!((m){ return divMod(20,m); })(iota(1, 20));
int[] firsts, seconds;
foreach (t; r) {
firsts ~= t[0];
seconds ~= t[1];
}
writeln(firsts);
writeln(seconds);
}
Output:
[20, 10, 6, 5, 4, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[0, 0, 2, 0, 0, 2, 6, 4, 2, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Similar code in Python shell:
>>> r = (divmod(20, m) for m in xrange(1,20))
>>> firsts, seconds = zip(*r)
>>> firsts
(20, 10, 6, 5, 4, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1)
>>> seconds
(0, 0, 2, 0, 0, 2, 6, 4, 2, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1)
In Phobos a higher-order function to perform this operation may be named "unzip" as in Haskell. This unzip is generalizable to zips of more than two sequences:
unzip(zip([1,2,3], "abc", [0.5,1.0,1.5]))
Comment #1 by r9shackleford — 2015-05-14T12:25:21Z
I was looking for this in std.range and didn't find anything, came across this issue.
Since this is about 4 years old, was anything like this ever implemented?
Comment #2 by edder — 2015-09-07T09:55:37Z
(In reply to weaselcat from comment #1)
> I was looking for this in std.range and didn't find anything, came across
> this issue.
>
> Since this is about 4 years old, was anything like this ever implemented?
I was wondering the same thing.
Comment #3 by bearophile_hugs — 2015-09-18T08:57:32Z
(In reply to weaselcat from comment #1)
> I was looking for this in std.range and didn't find anything, came across
> this issue.
>
> Since this is about 4 years old, was anything like this ever implemented?
There are plenty of old ERs in bugzilla.
Comment #4 by kuettler — 2017-05-07T12:49:38Z
For forward ranges of tuples "unzip" can be implemented in a few lines. E.g.
import std.typecons, std.algorithm, std.range;
Tuple!(int,int) divMod(int n, int m) {
return tuple(n / m, n % m);
}
auto unzip(Range)(Range r)
if (isForwardRange!Range && isTuple!(ElementType!Range))
{
import std.conv;
auto generateElements(size_t length)
{
const s = iota(length)
.map!(i => "r.map!(t => t[" ~ i.to!string ~ "])")
.join(",");
return "tuple(" ~ s ~ ")";
}
alias T = ElementType!Range;
return mixin(generateElements(T.Types.length));
}
void main()
{
import std.stdio, std.array;
auto rs = iota(1, 20).map!(m => divMod(20,m)).unzip();
writeln(rs[0].array);
writeln(rs[1].array);
}
Not sure if this should go into phobos.
Comment #5 by greensunny12 — 2017-07-19T18:38:47Z
> For forward ranges of tuples "unzip" can be implemented in a few lines. E.g.
That's pretty sweet! I actually built something on top of this and was about to submit it:
https://github.com/dlang/phobos/compare/master...wilzbach:unzip
But then I realized that std.range.transversal already solves this nicely:
import std.algorithm, std.range, std.stdio;
int[][] x = new int[][3];
x[0] = [1, 2, 3];
x[1] = [4, 5, 6];
x.transversal(1).writeln; // [2, 5]
x.front.walkLength.iota.map!(i => transversal(x, i)).writeln; // [[1, 4], [2, 5], [3, 6]]
Plat with this online: https://is.gd/YYCgPk
So I'm inclined to close this as WORKSFORME - other opionions?
Comment #6 by andrei — 2017-07-25T20:39:26Z
(In reply to Seb from comment #5)
> > For forward ranges of tuples "unzip" can be implemented in a few lines. E.g.
>
> That's pretty sweet! I actually built something on top of this and was about
> to submit it:
>
> https://github.com/dlang/phobos/compare/master...wilzbach:unzip
>
> But then I realized that std.range.transversal already solves this nicely:
>
> import std.algorithm, std.range, std.stdio;
> int[][] x = new int[][3];
> x[0] = [1, 2, 3];
> x[1] = [4, 5, 6];
> x.transversal(1).writeln; // [2, 5]
> x.front.walkLength.iota.map!(i => transversal(x, i)).writeln; // [[1, 4],
> [2, 5], [3, 6]]
>
> Plat with this online: https://is.gd/YYCgPk
>
> So I'm inclined to close this as WORKSFORME - other opionions?
Seb, could you please copy the example you wrote in transversal? Also mention the feature can be found in other languages with the name "unzip", thus making the term searchable. It would close this bug. Thanks!
Comment #7 by github-bugzilla — 2017-08-24T08:17:41Z