D言語で unzip
D言語の標準ライブラリ Phobos には Haskell などでは有名な zip という関数が存在します。が、その逆となる unzip が存在しません...。
というわけで作りました。Range でもありませんし、非効率な実装ですが、D言語のメタプログラミングのしやすさが実感できました。
import std.meta : AliasSeq;
import std.traits : Unqual;
import std.typecons : Tuple, tuple;
auto toListTypes(Ts...)()
{
alias TypeList = AliasSeq!Ts;
string s;
foreach(t; TypeList)
{
s ~= Unqual!t.stringof ~ "[],";
}
return s[0..$-1];
}
unittest
{
enum result = toListTypes!(int, double, string)();
static assert(result == "int[],double[],string[]");
}
auto unzip(Ts...)(Tuple!(Ts)[] zipped)
{
mixin("Tuple!(" ~ toListTypes!Ts ~ ") result;");
const n = zipped.length;
foreach (j, T; AliasSeq!Ts)
{
result[j].length = n;
foreach (i; 0 .. n)
{
result[j][i] = zipped[i][j];
}
}
return result;
}
unittest
{
import std.range : array, zip;
immutable a = [1, 2, 3];
immutable b = ["a", "b", "c"];
immutable c = [0.1, 0.2, 0.3];
static assert(unzip(zip(a, b, c).array) == tuple(a, b, c));
}
foreach (j, T; AliasSeq!Ts)
のところに、enumerate
を使うとコンパイル通らないのがハマりどころです。
あとmixin(s);
するときはpragma(msg, s)
とするとコンパイル時にprint debugできて楽ですね。
参考
追記
何度目かわかりませんが、ローカルの jekyll をアップデートした際に壊れてしまいました...。 そろそろこのフォーマットで書き散らかすのもキツいので、年内には MDwiki に移行する計画です。 それに向けてブログ用として、小さなツールを D 言語で書いているこの頃です。