英語版
このページの英語版を見る
std.algorithm.iteration
これは std.algorithm.
一般的な反復アルゴリズムが含まれている。
関数名 | 説明 |
---|---|
cache | 他の範囲のfront を評価し、キャッシュする。 |
cacheBidirectional | 上記と同様だが、back とpopBack も提供する。 |
chunkBy | chunkBy!((a,b) => a[1] == b[1])([[1, 1], [1, 2], [2, 2], [2, 1]]) は3つのサブ範囲を含む範囲を返す。 [1, 1] 2番目は要素[1, 2] と[2, 2] ; そして3番目は[2, 1] だけである。 |
cumulativeFold | cumulativeFold!((a, b) => a + b)([1, 2, 3, 4]) は 1 を含む範囲を返す、 3 6 ,10 を返す。 |
each | each!writeln([1, 2, 3]) は、1 、2 と3 をそれぞれの行に表示する。 |
filter | filter!(a => a > 0)([1, -1, 2, 0, -3]) 要素1 および2 。 |
filterBidirectional | filter に似ているが、back とpopBack も提供している。 を提供する。 |
fold | fold!((a, b) => a + b)([1, 2, 3, 4]) は10 を返す。 |
group | group([5, 2, 2, 3, 3]) を含む範囲を返す。 tuple(5, 1) tuple(2, 2) tuple(3, 2) を含む範囲を返す。 |
joiner | joiner(["hello", "world!"], "; ") を反復する範囲を返す。 "hello; world!" を反復する範囲を返す。新しい文字列は作成されない。 既存の入力が反復される。 |
map | map!(a => a * 2)([1, 2, 3]) を含む範囲を返す。 2 4 ,6 を返す。 |
mean | 俗に平均として知られる、mean([1, 2, 3]) は2 を返す。 |
permutations | LazilyはHeapのアルゴリズムを使ってすべての順列を計算する。 |
reduce | reduce!((a, b) => a + b)([1, 2, 3, 4]) は10 を返す。 これはfold の古い実装である。 |
splitWhen | Lazily は隣接する要素を比較することで範囲を分割する。 |
splitter | Lazily はセパレータで範囲を分割する。 |
substitute | [1, 2].substitute(1, 0.1) は[0.1, 2] を返す。 |
sum | fold と同じだが、正確な合計のために特化されている。 |
uniq | ソートされていると仮定された範囲内のユニークな要素を繰り返し処理する。 |
License:
Authors:
- auto
cache
(Range)(Rangerange
)
if (isInputRange!Range);
autocacheBidirectional
(Range)(Rangerange
)
if (isBidirectionalRange!Range); cache
の前を熱心に評価する。range
を評価する、 をeagerlyに評価し、結果をキャッシュに保存する。 その結果は、frontが呼ばれたときに直接返される、 が呼び出されたときに直接返される。これは、高価な評価を必要とする関数の後に連鎖的に配置するのに便利な関数である。 の後段に置くのに便利な関数である。 std.array.array. を呼び出す前に置くことができる。 mapの呼び出しの後、あるいは std.range.filterまたは std.range.teecache
または 双方向レンジ の呼び出しによって明示的に要求する必要がある。 を呼び出して明示的に要求しなければならない。cacheBidirectional
.さらに、双方向キャッシュは は "中心 "要素を2回評価する。 を2回評価することになる。cache
はランダムアクセスプリミティブを提供しない、 そのためcache
はランダムアクセスをキャッシュできない。 Range 、スライシング・プリミティブを提供する、 ならばcache
も同じスライシング・プリミティブを提供する、 しかし、hasSlicing!Cache 。 std.range.primitives.hasSlicing トレイトもランダムアクセスをチェックするからだ)。Parameters:Range range
入力範囲 Returns:範囲のキャッシュ値を持つ入力範囲Examples:import std.algorithm.comparison : equal; import std.range, std.stdio; import std.typecons : tuple; ulong counter = 0; double fun(int x) { ++counter; // https://ja.wikipedia.org/wiki/四次函数 return ( (x + 4.0) * (x + 1.0) * (x - 1.0) * (x - 3.0) ) / 14.0 + 0.5; } // キャッシュなし、配列あり(貪欲) auto result1 = iota(-4, 5).map!(a =>tuple(a, fun(a)))() .filter!(a => a[1] < 0)() .map!(a => a[0])() .array(); // yが負となるxの値は次の通りである: assert(equal(result1, [-3, -2, 2])); // funが何回評価されたか確認する。 // ソースと結果の両方にある項目の数と同じ回数。 writeln(counter); // iota(-4, 5).length + result1.length counter = 0; // 配列なし、キャッシュあり(遅延) auto result2 = iota(-4, 5).map!(a =>tuple(a, fun(a)))() .cache() .filter!(a => a[1] < 0)() .map!(a => a[0])(); // yが負となるxの値は次の通りである: assert(equal(result2, [-3, -2, 2])); // funが何回評価されたか確認する。 // ソース内のアイテムの数と同じ回数だけ。 writeln(counter); // iota(-4, 5).length
Examples:ヒントcache
は要素を評価するときにeagerである。もし を呼び出す際に副作用がある場合、キャッシュされた実際の範囲に対して を呼び出す前に観測可能となる。 さらにcache
で std.range.take. の前にtake 。cache
の前に置くことでcache
の前に置くことで の前に置くことで、範囲がいつ終わるかを "認識 "し、必要なときに要素のキャッシュを正しく停止する。 frontを呼び出しても副作用がない場合は、take をcache
の後に置くと、より高速な範囲が得られるかもしれない。 いずれにせよ、結果として得られるレンジは同等になるが、同じコストや副作用ではないかもしれない。 同じコストや副作用ではないかもしれない。import std.algorithm.comparison : equal; import std.range; int i = 0; auto r = iota(0, 4).tee!((a){i = a;}, No.pipeOnPop); auto r1 = r.take(3).cache(); auto r2 = r.cache().take(3); assert(equal(r1, [0, 1, 2])); assert(i == 2); //最後に"見た"要素は、2.キャッシュのデータがクリアされた。 assert(equal(r2, [0, 1, 2])); assert(i == 3); //キャッシュは3にアクセスした。それは依然としてキャッシュによって内部的に保存されている。
- template
map
(fun...) if (fun.length >= 1) - 多くの関数型言語にある同音異義語関数(transform )を実装している。 を実装している。呼び出しは
map
!(fun)(range) を適用して得られる要素の範囲を返す。fun(a) a rangeを左から右に適用して得られる要素の範囲を返す。元の範囲は変更されない。 は変更されない。評価は遅延的に行われる。Parameters:fun つ以上の変換関数 See Also:Examples:import std.algorithm.comparison : equal; import std.range : chain, only; auto squares = chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a); assert(equal(squares, only(1, 4, 9, 16, 25, 36)));
Examples:に複数の関数を渡すことができる。map
.その場合 の要素型はタプルになる。map
の要素型は、各 関数ごとに1つの要素を含むタプルになる。auto sums = [2, 4, 6, 8]; auto products = [1, 4, 9, 16]; size_t i = 0; foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a")) { writeln(result[0]); // sums[i] writeln(result[1]); // products[i] ++i; }
Examples:シンボルにmap
をシンボルにエイリアスして使うことができる。 を別個に使うことができる:import std.algorithm.comparison : equal; import std.conv : to; alias stringize = map!(to!string); assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));
- auto
map
(Range)(Ranger
)
if (isInputRange!(Unqual!Range)); - Parameters:
Range r
入力範囲 Returns:各ファンがすべての要素に適用された範囲。複数の funが複数ある場合、要素の型はTuple 、それぞれのfunに対して1つの要素が含まれる。
- template
each
(alias fun = "a") - Eagerlyはr を繰り返し、各要素でfun を呼び出す。呼び出す関数が指定されていない場合、
each
呼び出す関数が指定されていない場合、デフォルトは何もしないが r.front が評価されるが、これは パラメータでラムダを指定することで回避できる。 lazy を指定することで回避できる。each
はopApply ベースの型もサポートしているので、例えば std.parallelism.parallel. 通常は全範囲が反復される。部分的反復(早期停止)が必要な場合 が必要な場合は、fun 。 std.typecons.Flag!"each
"(Yes.each
の値を返す必要がある。 No.each
を返す必要がある。 の値を返す必要がある。)Parameters:fun 範囲の各要素に適用する関数。 Range r の各要素に適用される。 each
イテレートするReturns:Yes.each
範囲全体が反復された場合 No.each
早期に 停止する。See Also:Examples:import std.range : iota; import std.typecons : No; int[] arr; iota(5).each!(n => arr ~= n); writeln(arr); // [0, 1, 2, 3, 4] // 早めに反復をやめる iota(5).each!((n) { arr ~= n; return No.each; }); writeln(arr); // [0, 1, 2, 3, 4, 0] // 範囲がサポートしている場合、値をその場で変更できる arr.each!((ref n) => n++); writeln(arr); // [1, 2, 3, 4, 5, 1] arr.each!"a++"; writeln(arr); // [2, 3, 4, 5, 6, 2] auto m = arr.map!(n => n); // 非参照範囲ではby-refラムダは許されない static assert(!__traits(compiles, m.each!((ref n) => n++))); // デフォルトの述語は範囲を消費する (&m).each(); assert(m.empty);
Examples:each
をサポートするイテレート可能なオブジェクトでは、インデックス変数を渡すことができる。auto arr = new size_t[4]; arr.each!"a=i"(); writeln(arr); // [0, 1, 2, 3] arr.each!((i, ref e) => e = i * 2); writeln(arr); // [0, 2, 4, 6]
Examples:opApplyイテレーターも同様に機能するstatic class S { int x; int opApply(scope int delegate(ref int _x) dg) { return dg(x); } } auto s = new S; s.each!"a++"; writeln(s.x); // 1
- Flag!"
each
"each
(Range)(Ranger
)
if (!isForeachIterable!Range && (isRangeIterable!Range || __traits(compiles, typeof(r
.front).length)));
Flag!"each
"each
(Iterable)(auto ref Iterabler
)
if (isForeachIterable!Iterable || __traits(compiles, Parameters!(Parameters!(r
.opApply)))); - Parameters:
Range r
それぞれが反復する範囲または反復可能範囲
- template
filter
(alias predicate) if (is(typeof(unaryFun!predicate))) filter
!(predicate)(range)は、range の要素x のみを含む新しい範囲を返す。 に対して、predicate(x) はtrue を返す。述語は std.functional.unaryFunに渡され、文字列または pred(element) を介して実行可能な任意の callable である。Parameters:predicate 範囲の各要素に適用する関数". Returns:フィルタリングされた要素を含む入力範囲。range 、少なくとも前方範囲であればfilter
の返り値も前方範囲になる。Examples:import std.algorithm.comparison : equal; import std.math.operations : isClose; import std.range; int[] arr = [ 1, 2, 3, 4, 5 ]; // 3以下をフィルタする auto small = filter!(a => a < 3)(arr); assert(equal(small, [ 1, 2 ])); // 統一関数呼び出し構文(UFCS)で再度フィルタリングする auto sum = arr.filter!(a => a < 3); assert(equal(sum, [ 1, 2 ])); // chain()と組み合わせて複数の範囲にまたがるようにする int[] a = [ 3, -2, 400 ]; int[] b = [ 100, -101, 102 ]; auto r = chain(a, b).filter!(a => a > 0); assert(equal(r, [ 3, 400, 100, 102 ])); // 変換可能な型を混在させることも可能である double[] c = [ 2.5, 3.0 ]; auto r1 = chain(c, a, b).filter!(a => cast(int) a != a); assert(isClose(r1, [ 2.5 ]));
- auto
filter
(Range)(Rangerange
)
if (isInputRange!(Unqual!Range)); - Parameters:
Range range
要素の入力範囲 要素の Returns:でx の要素のみを含む範囲。range
の要素のみを含む範囲。 で、predicate(x) がtrue を返す。
- template
filterBidirectional
(alias pred) - filter と似ている。 に似ている。 コンストラクタは、フィルタリングを満たす範囲の最後の要素を見つけるのに時間を費やす。 を満たす範囲の最後の要素を見つけるのに時間がかかる。 を満たす範囲の最後の要素を見つけるのに時間がかかる。利点は フィルタリングされた範囲が両方向からスパンできることである。また std.range.retroを適用することもできる。述語は std.functional.unaryFunに渡される。 に渡され、文字列か、pred(element) を介して実行できる任意の callable を受け取ることができる。Parameters:
pred 範囲の各要素に適用する関数". Examples:import std.algorithm.comparison : equal; import std.range; int[] arr = [ 1, 2, 3, 4, 5 ]; auto small = filterBidirectional!("a < 3")(arr); static assert(isBidirectionalRange!(typeof(small))); writeln(small.back); // 2 assert(equal(small, [ 1, 2 ])); assert(equal(retro(small), [ 2, 1 ])); // chain()との組み合わせで複数の範囲にまたがる int[] a = [ 3, -2, 400 ]; int[] b = [ 100, -101, 102 ]; auto r = filterBidirectional!("a > 0")(chain(a, b)); writeln(r.back); // 102
- auto
filterBidirectional
(Range)(Ranger
)
if (isBidirectionalRange!(Unqual!Range)); - Parameters:
Range r
エレメントの双方向範囲 Returns:の要素のみを含む範囲。r
の要素のみを含む範囲。pred はtrue を返す。
- Group!(pred, Range)
group
(alias pred = "a == b", Range)(Ranger
);
structGroup
(alias pred, R) if (isInputRange!R); - 連続的に等価な要素を、要素とその繰り返し数の1つのタプルにグループ化する。 のタプルにグループ化する。uniq と同様である、
group
は、与えられた範囲の一意な連続要素を反復する範囲を生成する。 を反復する範囲を生成する。この範囲の各要素は、要素 のタプルである。 要素の等価性は、述語pred を用いて評価される。 "a == b"に渡される。 std.functional.binaryFun, に渡され、文字列か、あるいは pred(element, element).Parameters:pred 2つの要素の等価性を判定する2値述語。 R 範囲型 Range r
入力範囲を を反復する。 Returns:Tuple!(ElementType!R, uint) 型の要素の範囲、 型の要素の範囲である。 型の要素の範囲。 これは、R が入力範囲である場合は入力範囲となる。 である場合は入力範囲となり、それ以外の場合は前方範囲となる。See Also:chunkBy入力範囲を隣接する等価な要素に分割する。 に分割する。Examples:import std.algorithm.comparison : equal; import std.typecons : tuple, Tuple; int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u), tuple(4, 3u), tuple(5, 1u) ][]));
Examples:groupを使えば、範囲内の一意な各要素のカウントを持つ連想配列を簡単に生成できる。 を持つ連想配列を簡単に生成できる。import std.algorithm.sorting : sort; import std.array : assocArray; uint[string] result; auto range = ["a", "b", "a", "c", "b", "c", "c", "d", "e"]; result = range.sort!((a, b) => a < b) .group .assocArray; writeln(result); // ["a":2U, "b":2U, "c":3U, "d":1U, "e":1U]
- auto
chunkBy
(alias pred, Range)(Ranger
)
if (isInputRange!Range); - 入力範囲を、等価な隣接要素の部分範囲に分割する。 他の言語では、これはしばしばpartitionBy と呼ばれる、groupBy またはsliceWhen と呼ばれる。等価性は述語pred で定義される。 に渡される。 std.functional.binaryFunに渡されるバイナリか に渡される。 std.functional.unaryFun.に渡される単項式である。 a とb は、pred(a,b) が真であれば等価とみなされる。単項式では が真の場合、2つの要素は等価とみなされる。pred(a) == pred(b) が真の場合、2つの要素は等価とみなされる。 この述語は同値関係でなければならない。 反射的 (pred(x,x) は常に真である)、対称的 (pred(x,y) == pred(y,x))、他動的(pred(x,y) && pred(y,z) はpred(x,z))でなければならない。そうでない場合、チャンクバイが返す範囲は、実行時にアサートされる可能性がある。 が返す範囲は、実行時にアサートされたり、挙動がおかしくなったりする。使用方法 splitWhen を使用する。Parameters:
pred 等価性を判断するための述語。 Range r
チャンクされる入力範囲。 Returns:バイナリ述語では、以下のような範囲が返される。 与えられた部分範囲のすべての要素は、与えられた述語の下で等価である。 単項述語では、タプルの範囲が返される。 タプルは、各サブレンジに対する単項述語の結果と タプルが返される。現在、範囲のコピーは参照セマンティクスを持つが、これは将来変更される可能性がある。 将来変更されるかもしれない。注釈 非等価要素によって区切られた等価要素は、別々のサブ範囲に表示される。 この"関数"は隣接する等価要素のみを考慮する。 のみを考慮する。この関数は隣接する等価要素のみを考慮する。 で表示される。
See Also:groupこれは、隣接する等価要素を1つの要素に折りたたむものである。 要素に折りたたむ。Examples:二項述語を使った用法を示す:import std.algorithm.comparison : equal; // 各要素の特定の属性でグループ化する: auto data = [ [1, 1], [1, 2], [2, 2], [2, 3] ]; auto r1 = data.chunkBy!((a,b) => a[0] == b[0]); assert(r1.equal!equal([ [[1, 1], [1, 2]], [[2, 2], [2, 3]] ])); auto r2 = data.chunkBy!((a,b) => a[1] == b[1]); assert(r2.equal!equal([ [[1, 1]], [[1, 2], [2, 2]], [[2, 3]] ]));
Examples:単項述語を使った用法を示す:import std.algorithm.comparison : equal; import std.range.primitives; import std.typecons : tuple; // 各要素の特定の属性でグループ化する: auto range = [ [1, 1], [1, 1], [1, 2], [2, 2], [2, 3], [2, 3], [3, 3] ]; auto byX = chunkBy!(a => a[0])(range); auto expected1 = [ tuple(1, [[1, 1], [1, 1], [1, 2]]), tuple(2, [[2, 2], [2, 3], [2, 3]]), tuple(3, [[3, 3]]) ]; foreach (e; byX) { assert(!expected1.empty); writeln(e[0]); // expected1.front[0] assert(e[1].equal(expected1.front[1])); expected1.popFront(); } auto byY = chunkBy!(a => a[1])(range); auto expected2 = [ tuple(1, [[1, 1], [1, 1]]), tuple(2, [[1, 2], [2, 2]]), tuple(3, [[2, 3], [2, 3], [3, 3]]) ]; foreach (e; byY) { assert(!expected2.empty); writeln(e[0]); // expected2.front[0] assert(e[1].equal(expected2.front[1])); expected2.popFront(); }
- auto
splitWhen
(alias pred, Range)(Ranger
)
if (isForwardRange!Range); - バイナリ述語によって決定される場所で、前方範囲をサブ範囲に分割する。 述語によって決定される場所でサブ範囲に分割する。反復するとき
r
の1つの要素は、pred と比較される。 要素と比較される。もしpred が真を返せば、次の要素に対して新しい部分範囲が開始される。 そうでなければ、それらは同じ部分範囲の一部である。 要素が不等号(!=)演算子で比較される場合は、次のように考える。 chunkByその方が実行速度が速いだろうからである。Parameters:pred どこで分割するかを決定するための述語。の最初の要素が常に最初の引数として与えられる。 が常に最初の引数として与えられる。 Range r
分割される前方範囲。 Returns:のサブレンジの範囲。r
の部分範囲の範囲であり、与えられた部分範囲内で分割される、 隣接する要素の任意のペアを引数としてpred を呼び出すと、false が返される。 範囲のコピーは現在参照セマンティクスを持つが、これは将来変更される可能性がある。See Also:splitterこれは要素間の関係ではなく、要素をスプリッターとして使用する。 関係を使用する。Examples:import std.algorithm.comparison : equal; import std.range : dropExactly; auto source = [4, 3, 2, 11, 0, -3, -3, 5, 3, 0]; auto result1 = source.splitWhen!((a,b) => a <= b); assert(result1.save.equal!equal([ [4, 3, 2], [11, 0, -3], [-3], [5, 3, 0] ])); //splitWhenは、chunkByと同様に、現在は参照範囲である(将来的に //変更される可能性がある)。適切なタイミングで`save`を呼び出すことを忘れないように。 auto result2 = result1.dropExactly(2); assert(result1.save.equal!equal([ [-3], [5, 3, 0] ]));
- auto
joiner
(RoR, Separator)(RoRr
, Separatorsep
);
autojoiner
(RoR)(RoRr
)
if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR))); - セパレータで範囲の範囲を緩やかに結合する。セパレータ自体 は範囲である。セパレータが指定されない場合、範囲は と呼ばれる)。flatten と呼ばれる)。Returns:結合範囲内の要素の範囲。以下の場合は双方向範囲となる。 RoR の外側範囲と内側範囲の両方が少なくとも双方向範囲であれば、これは双方向範囲となる。もし RoR の外側と内側の両方の範囲が少なくとも双方向範囲であれば、これは双方向範囲となる。 も同様である。そうでない場合は、単なる入力範囲となる。この 範囲の双方向性 は、セパレータが指定されなければ伝播される。See Also:std.range.chainこれは、互換性のある要素を持つ一連の範囲を1つの範囲に連結するものである。 を1つの範囲に連結する。
注釈: RoR 、外側と内側の両方の範囲が双方向であり、ジョイナーが後ろから前に反復される場合、セパレーターは後ろから前に消費される。 が後方から前方へ反復される場合、セパレータは前方から後方へ消費される。 を消費する。
Examples:import std.algorithm.comparison : equal; import std.conv : text; assert(["abc", "def"].joiner.equal("abcdef")); assert(["Mary", "has", "a", "little", "lamb"] .joiner("...") .equal("Mary...has...a...little...lamb")); assert(["", "abc"].joiner("xyz").equal("xyzabc")); assert([""].joiner("xyz").equal("")); assert(["", ""].joiner("xyz").equal("xyz"));
Examples:import std.algorithm.comparison : equal; import std.range : repeat; assert([""].joiner.equal("")); assert(["", ""].joiner.equal("")); assert(["", "abc"].joiner.equal("abc")); assert(["abc", ""].joiner.equal("abc")); assert(["abc", "def"].joiner.equal("abcdef")); assert(["Mary", "has", "a", "little", "lamb"].joiner.equal("Maryhasalittlelamb")); assert("abc".repeat(3).joiner.equal("abcabcabc"));
Examples:ジョイナーはインプレース変異を可能にする!import std.algorithm.comparison : equal; auto a = [ [1, 2, 3], [42, 43] ]; auto j = joiner(a); j.front = 44; writeln(a); // [[44, 2, 3], [42, 43]] assert(equal(j, [44, 2, 3, 42, 43]));
Examples:文字列の中に文字をゆったりと挿入するimport std.algorithm.comparison : equal; import std.range : chain, cycle, iota, only, retro, take, zip; import std.format : format; static immutable number = "12345678"; static immutable delimiter = ","; auto formatted = number.retro .zip(3.iota.cycle.take(number.length)) .map!(z => chain(z[0].only, z[1] == 2 ? delimiter : null)) .joiner .retro; static immutable expected = "12,345,678"; assert(formatted.equal(expected));
Examples:ジョイナーは双方向に使用できるimport std.algorithm.comparison : equal; import std.range : retro; auto a = [[1, 2, 3], [4, 5]]; auto j = a.joiner; j.back = 44; writeln(a); // [[1, 2, 3], [4, 44]] assert(equal(j.retro, [44, 4, 3, 2, 1]));
- template
reduce
(fun...) if (fun.length >= 1) - 様々な関数型言語に存在する同音異義語関数(accumulate 、compress 、inject 、foldl としても知られている)を実装している。 を実装している。また foldもある。 もあるが、これはパラメータの順序が逆である。 呼び出しは
reduce
!(fun)(seed, range)呼び出しは、まずseed を を内部変数result に代入する。 次に、range の各要素x が評価される、result = fun(result, x) の各要素が評価される。最後に、result が返される。 引数1つのバージョンreduce
!(fun)(range) は同様に動作するが、範囲の最初の要素をシードとして使用する(範囲は空であってはならない)。 として使用する(範囲は空であってはならない)。Returns:累積されたresultParameters:fun 一つ以上の関数 See Also:フォールド(高次関数) foldと関数的には等価である。 reduceに相当する。 を使う必要がない。 tuple を使う必要がない。これにより、UFCSチェーンでの使用が容易になる。 sumはreduce
!((a, b) => a + b)に似ている。 に似ている。Examples:多くの範囲演算はreduce
を使って素早く簡単に解くことができる。以下の例では、以下のようになる。reduce
's の驚くべきパワーと柔軟性を示している。import std.algorithm.comparison : max, min; import std.math.operations : isClose; import std.range; int[] arr = [ 1, 2, 3, 4, 5 ]; // すべての要素を合計する auto sum = reduce!((a,b) => a + b)(0, arr); writeln(sum); // 15 // "a"と"b"の文字列述語を使って再度合計する sum = reduce!"a + b"(0, arr); writeln(sum); // 15 // すべての要素の最大値を計算する auto largest = reduce!(max)(arr); writeln(largest); // 5 // 再び最大値を計算するが、統一関数呼び出し構文(UFCS)を使用する largest = arr.reduce!(max); writeln(largest); // 5 // 奇数要素の数を計算する auto odds = reduce!((a,b) => a + (b & 1))(0, arr); writeln(odds); // 3 // 平方和を計算する auto ssquares = reduce!((a,b) => a + b * b)(0, arr); writeln(ssquares); // 55 // 複数の範囲をシードに連結する int[] a = [ 3, 4 ]; int[] b = [ 100 ]; auto r = reduce!("a + b")(chain(a, b)); writeln(r); // 107 // 変換可能な型を混在させることも可能である double[] c = [ 2.5, 3.0 ]; auto r1 = reduce!("a + b")(chain(a, b, c)); assert(isClose(r1, 112.5)); // 括弧の入れ子を最小限にするために、統一関数呼び出し構文を使うことができる auto r2 = chain(a, b, c).reduce!("a + b"); assert(isClose(r2, 112.5));
Examples:時には、1回のパスで複数の集約を計算することは非常に便利である。 一つの利点は、ループのオーバーヘッドが共有されるため、計算が速くなることである。 が共有される。これがreduce
は複数の関数を受け付ける。 2つ以上の関数が渡されるとreduce
を返す。 std.typecons.Tupleオブジェクトを返す。 それに応じてシードの数も増やさなければならない。import std.algorithm.comparison : max, min; import std.math.operations : isClose; import std.math.algebraic : sqrt; import std.typecons : tuple, Tuple; double[] a = [ 3.0, 4, 7, 11, 3, 2, 5 ]; // 最小値と最大値を一度に計算する auto r = reduce!(min, max)(a); // rの型はTuple!(int, int)である assert(isClose(r[0], 2)); // 最小 assert(isClose(r[1], 11)); // 最大 // 和と平方和を一度に計算する r = reduce!("a + b", "a + b * b")(tuple(0.0, 0.0), a); assert(isClose(r[0], 35)); // 和 assert(isClose(r[1], 233)); // 平方和 // 上記から平均と標準偏差を計算する auto avg = r[0] / a.length; writeln(avg); // 5 auto stdev = sqrt(r[1] / a.length - avg * avg); writeln(cast(int)stdev); // 2
- auto
reduce
(R)(Rr
)
if (isIterable!R); - ノーシードバージョン。の最初の要素がシードの値として使われる。
r
の最初の要素がシードの値として使われる。fun の各関数f に対して、対応するシード型 は である。 S e 、対応するシード型はUnqual!(typeof(f(e, e))) である。 の要素である。r
ElementType!R である、 ForeachType!R の要素である。 Sが決まれば、S s = e; とs = f(s, e); の両方が合法でなければならない。Parameters:R r
で定義される反復可能な値である。isIterable Returns:で定義される反復可能な値。Throws:Exception もしr
が空の場合 - auto
reduce
(S, R)(Sseed
, Rr
)
if (isIterable!R); - シードのバージョン。fun 、シードは単一値でなければならない。 である場合、シードは単一の値でなければならない。fun が複数関数の場合は、次のようになる。
seed
でなければならない。 std.typecons.Tupleでなければならない。f の関数ごとにフィールドが1つずつある。便宜上、シードがconstの場合、または修飾フィールドを持つ場合は、次のようにする。reduce
は修飾されていないコピーを操作する。この場合 の場合、返される型はS と完全には一致しない。 の代わりにfold を使う。reduce
を使う。Parameters:S seed
アキュムレータの初期値 R r
で定義される反復可能な値である。isIterable Returns:アキュムレータの最終結果を反復可能な値に適用する。
- template
fold
(fun...) if (fun.length >= 1) - 様々な関数型言語に存在する同音異義語関数(accumulate 、compress 、inject 、foldl としても知られている)を実装する。 を実装し、1つ以上の述語を繰り返し呼び出す。
fun の各述語は2つの引数を取らなければならない:
- アキュムレータ値
- 範囲の要素r
各述語は、暗黙のうちにアキュムレータの型に変換する値を返さなければならない。 型に暗黙的に変換する値を返さなければならない。
単一の述語に対して 呼び出しは
fold
!(fun)(range, seed)となる:- seed 、内部変数result (アキュムレーターとも呼ばれる)を初期化する。 を初期化する。)
- range の各要素e に対して、result = fun(result, e) を評価する。
- result を返す。
1引数バージョン
複数の述語を使用すると、複数の結果が生成される。fold
!(fun)(range) は同様に動作するが、範囲の最初の要素を として使用し(範囲は空であってはならない)、残りの 要素を反復処理する。Parameters:fun 要素に適用する述語関数。 See Also:- 折りたたむ(高階関数)
- sumは
fold
!((a, b) => a + b)に似ている。 に似ている。 fold
と関数的には等価である。 reduceと機能的に等価である。 を使う必要がない。 tuple を使う必要がない。
Examples:immutable arr = [1, 2, 3, 4, 5]; // すべての要素を合計する writeln(arr.fold!((a, e) => a + e)); // 15 // すべての要素を明示的なシードで合計する writeln(arr.fold!((a, e) => a + e)(6)); // 21 import std.algorithm.comparison : min, max; import std.typecons : tuple; // 最小値と最大値を同時に計算する writeln(arr.fold!(min, max)); // tuple(1, 5) // シードを使って最小値と最大値を同時に計算する writeln(arr.fold!(min, max)(0, 7)); // tuple(0, 7) // UFCSチェーンで使用できる writeln(arr.map!(a => a + 1).fold!((a, e) => a + e)); // 20 // 任意の範囲の最後の要素を返す writeln(arr.fold!((a, e) => e)); // 5
- template
cumulativeFold
(fun...) if (fun.length >= 1) - fold に似ているが、連続する削減値を含む範囲を返す。 この呼び出しは
cumulativeFold
!(fun)(range, seed)呼び出しは、まずseed を内部変数 resultに代入する。 返される範囲には、result = fun(result, x) の各要素 に対して遅延評価された値 が含まれる。 rangeの各要素x に対して評価された値が含まれる。最後に、最後の要素は fold!(fun)(seed, range) と同じ値を持つ。 引数1つのバージョンcumulativeFold
!(fun)(range)も同様に動作するが の各要素が評価される。 要素のシードとして使用する。 この関数は次のようにも知られている。 としても知られている、 accumulateとしても知られている、 スキャンとも呼ばれる、 累積和。Parameters:fun 折りたたみ演算として使用する1つ以上の関数 Returns:See Also:注釈:」である。 関数型プログラミング言語では、これは通常scan 、scanl と呼ばれる、 scanLeft またはreductions と呼ばれる。
Examples:import std.algorithm.comparison : max, min; import std.array : array; import std.math.operations : isClose; import std.range : chain; int[] arr = [1, 2, 3, 4, 5]; // すべての要素の部分和を返す auto sum = cumulativeFold!((a, b) => a + b)(arr, 0); writeln(sum.array); // [1, 3, 6, 10, 15] // "a"と"b"の文字列述語を使って、再び部分和を返す auto sum2 = cumulativeFold!"a + b"(arr, 0); writeln(sum2.array); // [1, 3, 6, 10, 15] // 全要素の部分最大値を計算する auto largest = cumulativeFold!max(arr); writeln(largest.array); // [1, 2, 3, 4, 5] // 再び部分最大値を計算するが、統一関数呼び出し構文(UFCS)を使用する largest = arr.cumulativeFold!max; writeln(largest.array); // [1, 2, 3, 4, 5] // 奇数要素の部分カウント auto odds = arr.cumulativeFold!((a, b) => a + (b & 1))(0); writeln(odds.array); // [1, 1, 2, 2, 3] // 平方部分和を計算する auto ssquares = arr.cumulativeFold!((a, b) => a + b * b)(0); writeln(ssquares.array); // [1, 5, 14, 30, 55] // 複数の範囲をシードに連結する int[] a = [3, 4]; int[] b = [100]; auto r = cumulativeFold!"a + b"(chain(a, b)); writeln(r.array); // [3, 7, 107] // 変換可能な型を混在させることも可能である double[] c = [2.5, 3.0]; auto r1 = cumulativeFold!"a + b"(chain(a, b, c)); assert(isClose(r1, [3, 7, 107, 109.5, 112.5])); // 括弧の入れ子を最小限にするために、統一関数呼び出し構文を使うことができる auto r2 = chain(a, b, c).cumulativeFold!"a + b"; assert(isClose(r2, [3, 7, 107, 109.5, 112.5]));
Examples:時には、1回のパスで複数の集約を計算することは非常に便利である。 一つの利点は、ループのオーバーヘッドが共有されるため、計算が速くなることである。 が共有される。これがcumulativeFold
は複数の関数を受け付ける。 2つ以上の関数が渡されるとcumulativeFold
を返す。 std.typecons.Tupleオブジェクトを返す。 それに応じてシードの数も増やさなければならない。import std.algorithm.comparison : max, min; import std.algorithm.iteration : map; import std.math.operations : isClose; import std.typecons : tuple; double[] a = [3.0, 4, 7, 11, 3, 2, 5]; // 最小値と最大値を一度に計算する auto r = a.cumulativeFold!(min, max); // rの型はTuple!(int, int)である assert(isClose(r.map!"a[0]", [3, 3, 3, 3, 3, 2, 2])); // 最小 assert(isClose(r.map!"a[1]", [3, 4, 7, 11, 11, 11, 11])); // 最大 // 和と平方和を一度に計算する auto r2 = a.cumulativeFold!("a + b", "a + b * b")(tuple(0.0, 0.0)); assert(isClose(r2.map!"a[0]", [3, 7, 14, 25, 28, 30, 35])); // 和 assert(isClose(r2.map!"a[1]", [9, 25, 74, 195, 204, 208, 233])); // 平方和
- auto
cumulativeFold
(R)(Rrange
)
if (isInputRange!(Unqual!R)); - シードなしバージョン。r の最初の要素がシードの値として使われる。 fun の各関数f に対して、対応するシード型S は以下の通りである。 Unqual!(typeof(f(e, e))) ここで、e はr の要素である: ElementType!R. S が決定されたら、S s = e; とs = f(s, e); は両方とも合法でなければならない。 は両方とも合法でなければならない。Parameters:
R range
入力範囲 Returns:連続した縮小値を含む範囲。 - auto
cumulativeFold
(R, S)(Rrange
, Sseed
)
if (isInputRange!(Unqual!R)); - シードのバージョン。fun が単一関数の場合、シードは単一値でなければならない。 は単一の値でなければならない。fun 、複数関数の場合は
seed
でなければならない。 std.typecons.Tupleでなければならない。f の関数ごとにフィールドが1つずつある。 便宜上、シードがconst 、または修飾されたフィールドを持つ場合は、次のようにする。cumulativeFold
は修飾されていないコピーを操作する。この場合 の場合、返される型はS と完全には一致しない。Parameters:R range
入力範囲 S seed
アキュムレータの初期値 Returns:連続した減少値を含む範囲。
- auto
splitter
(alias pred = "a == b", Flag!"keepSeparators" keepSeparators = No.keepSeparators, Range, Separator)(Ranger
, Separators
)
if (is(typeof(binaryFun!pred(r
.front,s
)) : bool) && (hasSlicing!Range && hasLength!Range || isNarrowString!Range));
autosplitter
(alias pred = "a == b", Flag!"keepSeparators" keepSeparators = No.keepSeparators, Range, Separator)(Ranger
, Separators
)
if (is(typeof(binaryFun!pred(r
.front,s
.front)) : bool) && (hasSlicing!Range || isNarrowString!Range) && isForwardRange!Separator && (hasLength!Separator || isNarrowString!Separator));
autosplitter
(alias isTerminator, Range)(Ranger
)
if (isForwardRange!Range && is(typeof(unaryFun!isTerminator(r
.front)))); - Lazily は、要素または範囲をセパレータとして使用して範囲を分割する。 セパレータの範囲は、任意の狭い文字列型やスライス可能な範囲型にすることができる。隣接する2つのセパレータは、分割範囲内の空の要素を囲むとみなされる。 を囲むとみなされる。空の要素を圧縮するには、結果にfilter!(a => !a.empty) を使用する。 を使用する。 述語は std.functional.binaryFunに渡され を介して実行される呼び出し可能な関数を受け取る。 pred(element,
s
).注釈 文字列を空白で分割し、トークンを圧縮したい場合は 区切り文字を指定せずに
セパレータが渡されない場合 isTerminator の要素を受け入れるかどうかを決定する。splitter
を使うことを検討すること。r
.Parameters:pred 各要素をセパレータと比較するための述語、 デフォルトは"a == b" である。 Range r
分割する入力範囲 分割される入力範囲。スライスと.length をサポートするか、狭い文字列型でなければならない。 Separator s
分割される範囲セグメント間のセパレータとして扱われる要素(または範囲)。 分割される範囲セグメント間の区切りとして扱われる要素(または範囲)。 isTerminator セパレータが渡されない場合に、範囲をどこで分割するかを決定するための述語。 keepSeparators セパレータを保持するかどうかを決定するフラグ。 制約 述語pred は
r
の要素と セパレータs
.Returns:See Also:std.regex.splitter正規表現で定義されたセパレーターを使って分割するバージョンについては、こちらを参照のこと、 std.array.splitを使って分割するバージョンには splitWhenは、セパレータに対する要素の代わりに隣接する要素を比較する。Examples:文字と数字による基本的な分割。import std.algorithm.comparison : equal; assert("a|bc|def".splitter('|').equal([ "a", "bc", "def" ])); int[] a = [1, 0, 2, 3, 0, 4, 5, 6]; int[][] w = [ [1], [2, 3], [4, 5, 6] ]; assert(a.splitter(0).equal(w));
Examples:文字と数字を使った基本的なスプリットと、センチネルをキープする。import std.algorithm.comparison : equal; import std.typecons : Yes; assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|') .equal([ "a", "|", "bc", "|", "def" ])); int[] a = [1, 0, 2, 3, 0, 4, 5, 6]; int[][] w = [ [1], [0], [2, 3], [0], [4, 5, 6] ]; assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w));
Examples:隣接するセパレーター。import std.algorithm.comparison : equal; assert("|ab|".splitter('|').equal([ "", "ab", "" ])); assert("ab".splitter('|').equal([ "ab" ])); assert("a|b||c".splitter('|').equal([ "a", "b", "", "c" ])); assert("hello world".splitter(' ').equal([ "hello", "", "world" ])); auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; auto w = [ [1, 2], [], [3], [4, 5], [] ]; assert(a.splitter(0).equal(w));
Examples:隣接するセパレーターと歩哨を守る。import std.algorithm.comparison : equal; import std.typecons : Yes; assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|') .equal([ "", "|", "ab", "|", "" ])); assert("ab".splitter!("a == b", Yes.keepSeparators)('|') .equal([ "ab" ])); assert("a|b||c".splitter!("a == b", Yes.keepSeparators)('|') .equal([ "a", "|", "b", "|", "", "|", "c" ])); assert("hello world".splitter!("a == b", Yes.keepSeparators)(' ') .equal([ "hello", " ", "", " ", "world" ])); auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; auto w = [ [1, 2], [0], [], [0], [3], [0], [4, 5], [0], [] ]; assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w));
Examples:空とセパレータのみの範囲。import std.algorithm.comparison : equal; import std.range : empty; assert("".splitter('|').empty); assert("|".splitter('|').equal([ "", "" ])); assert("||".splitter('|').equal([ "", "", "" ]));
Examples:射撃場を空にしてセパレーターだけにし、歩哨を配置する。import std.algorithm.comparison : equal; import std.typecons : Yes; import std.range : empty; assert("".splitter!("a == b", Yes.keepSeparators)('|').empty); assert("|".splitter!("a == b", Yes.keepSeparators)('|') .equal([ "", "|", "" ])); assert("||".splitter!("a == b", Yes.keepSeparators)('|') .equal([ "", "|", "", "|", "" ]));
Examples:分割に範囲を使うimport std.algorithm.comparison : equal; assert("a=>bc=>def".splitter("=>").equal([ "a", "bc", "def" ])); assert("a|b||c".splitter("||").equal([ "a|b", "c" ])); assert("hello world".splitter(" ").equal([ "hello", "world" ])); int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ]; assert(a.splitter([0, 0]).equal(w)); a = [ 0, 0 ]; assert(a.splitter([0, 0]).equal([ (int[]).init, (int[]).init ])); a = [ 0, 0, 1 ]; assert(a.splitter([0, 0]).equal([ [], [1] ]));
Examples:分割に範囲を使うimport std.algorithm.comparison : equal; import std.typecons : Yes; assert("a=>bc=>def".splitter!("a == b", Yes.keepSeparators)("=>") .equal([ "a", "=>", "bc", "=>", "def" ])); assert("a|b||c".splitter!("a == b", Yes.keepSeparators)("||") .equal([ "a|b", "||", "c" ])); assert("hello world".splitter!("a == b", Yes.keepSeparators)(" ") .equal([ "hello", " ", "world" ])); int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [0, 0], [3, 0, 4, 5, 0] ]; assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]).equal(w)); a = [ 0, 0 ]; assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]) .equal([ (int[]).init, [0, 0], (int[]).init ])); a = [ 0, 0, 1 ]; assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]) .equal([ [], [0, 0], [1] ]));
Examples:カスタム述語関数。import std.algorithm.comparison : equal; import std.ascii : toLower; assert("abXcdxef".splitter!"a.toLower == b"('x').equal( [ "ab", "cd", "ef" ])); auto w = [ [0], [1], [2] ]; assert(w.splitter!"a.front == b"(1).equal([ [[0]], [[2]] ]));
Examples:カスタム述語関数。import std.algorithm.comparison : equal; import std.typecons : Yes; import std.ascii : toLower; assert("abXcdxef".splitter!("a.toLower == b", Yes.keepSeparators)('x') .equal([ "ab", "X", "cd", "x", "ef" ])); auto w = [ [0], [1], [2] ]; assert(w.splitter!("a.front == b", Yes.keepSeparators)(1) .equal([ [[0]], [[1]], [[2]] ]));
Examples:セパレーターなしでスプリッターを使用するimport std.algorithm.comparison : equal; import std.range.primitives : front; assert(equal(splitter!(a => a == '|')("a|bc|def"), [ "a", "bc", "def" ])); assert(equal(splitter!(a => a == ' ')("hello world"), [ "hello", "", "world" ])); int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; int[][] w = [ [1, 2], [], [3], [4, 5], [] ]; assert(equal(splitter!(a => a == 0)(a), w)); a = [ 0 ]; assert(equal(splitter!(a => a == 0)(a), [ (int[]).init, (int[]).init ])); a = [ 0, 1 ]; assert(equal(splitter!(a => a == 0)(a), [ [], [1] ])); w = [ [0], [1], [2] ]; assert(equal(splitter!(a => a.front == 1)(w), [ [[0]], [[2]] ]));
Examples:先頭のセパレータ、末尾のセパレータ、またはセパレータなし。import std.algorithm.comparison : equal; assert("|ab|".splitter('|').equal([ "", "ab", "" ])); assert("ab".splitter('|').equal([ "ab" ]));
Examples:先頭のセパレータ、末尾のセパレータ、またはセパレータなし。import std.algorithm.comparison : equal; import std.typecons : Yes; assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|') .equal([ "", "|", "ab", "|", "" ])); assert("ab".splitter!("a == b", Yes.keepSeparators)('|') .equal([ "ab" ]));
Examples:スプリッターは、区切り文字が単一要素の場合、双方向の範囲を返す。import std.algorithm.comparison : equal; import std.range : retro; assert("a|bc|def".splitter('|').retro.equal([ "def", "bc", "a" ]));
Examples:スプリッターは、区切り文字が単一要素の場合、双方向の範囲を返す。import std.algorithm.comparison : equal; import std.typecons : Yes; import std.range : retro; assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|') .retro.equal([ "def", "|", "bc", "|", "a" ]));
Examples:単語でダラダラと分割するimport std.ascii : isWhite; import std.algorithm.comparison : equal; import std.algorithm.iteration : splitter; string str = "Hello World!"; assert(str.splitter!(isWhite).equal(["Hello", "World!"]));
- auto
splitter
(Range)(Ranges
)
if (isSomeString!Range || isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && !isConvertibleToString!Range && isSomeChar!(ElementEncodingType!Range)); - 文字ベースの範囲
s
空白を区切り文字として で区切る。この関数は文字範囲に特化したもので、以下の関数とは異なる。splitter
!(std.uni.isWhite)とは異なり、空白を含む単語はマージされる (空トークンは生成されない)。Parameters:Range s
分割する文字ベースの範囲。文字列、または ランダムアクセス可能な文字型の範囲でなければならない。 Returns:入力範囲は のスライスの入力範囲。Examples:import std.algorithm.comparison : equal; auto a = " a bcd ef gh "; assert(equal(splitter(a), ["a", "bcd", "ef", "gh"][]));
- template
substitute
(substs...) if (substs.length >= 2 && isExpressions!substs)
autosubstitute
(alias pred = (a, b) => a == b, R, Substs...)(Rr
, Substssubsts
)
if (isInputRange!R && (Substs.length >= 2) && !is(CommonType!Substs == void)); - が出現するすべての範囲を返す。
substs
が出現するr
. が置換された範囲を返す。単一値置換('ö'.substitute
!('ä', 'a', 'ö', 'o', 'ü', 'u))もサポートされている。 1もサポートされている。Parameters:R r
入力範囲 Value value Ο(1) に代入できる単一の値。 Substs substs
置換/代入の集合 pred 要素(複数可)が等しいかどうかをテストする等号関数。 置換 Returns:置換を置き換えた範囲See Also:Examples:import std.algorithm.comparison : equal; // 単一要素を置換する assert("do_it".substitute('_', ' ').equal("do it")); // 複数の単一要素を代入する assert("do_it".substitute('_', ' ', 'd', 'g', 'i', 't', 't', 'o') .equal("go to")); // 部分範囲の置換 assert("do_it".substitute("_", " ", "do", "done") .equal("done it")); // 置換はどのElementTypeに対しても機能する int[] x = [1, 2, 3]; auto y = x.substitute(1, 0.1); assert(y.equal([0.1, 2, 3])); static assert(is(typeof(y.front) == double)); import std.range : retro; assert([1, 2, 3].substitute(1, 0.1).retro.equal([3, 2, 0.1]));
Examples:より高速なコンパイル時オーバーロードを使用するimport std.algorithm.comparison : equal; // 範囲の部分範囲を置換する assert("apple_tree".substitute!("apple", "banana", "tree", "shrub").equal("banana_shrub")); // 範囲の部分範囲を置換する assert("apple_tree".substitute!('a', 'b', 't', 'f').equal("bpple_free")); // 値を置換する writeln('a'.substitute!('a', 'b', 't', 'f')); // 'b'
Examples:複数の代替選手import std.algorithm.comparison : equal; import std.range.primitives : ElementType; int[3] x = [1, 2, 3]; auto y = x[].substitute(1, 0.1) .substitute(0.1, 0.2); static assert(is(typeof(y.front) == double)); assert(y.equal([0.2, 2, 3])); auto z = "42".substitute('2', '3') .substitute('3', '1'); static assert(is(ElementType!(typeof(z)) == dchar)); assert(equal(z, "41"));
- auto
substitute
(Value)(Valuevalue
)
if (isInputRange!Value || !is(CommonType!(Value, typeof(substs[0])) == void)); - コンパイル時の置換マッピングで単一値を置換する。
複雑さ D のswitch がΟ(1)を保証しているため、Ο(1)となる;
- auto
sum
(R)(Rr
)
if (isInputRange!R && !isInfinite!R && is(typeof(r
.front +r
.front)));
autosum
(R, E)(Rr
, Eseed
)
if (isInputRange!R && !isInfinite!R && is(typeof(seed
=seed
+r
.front))); - の要素を合計する。
r
の要素を合計する。 の要素を合計する。概念的には 概念的にはsum
(r
)と等価である。 foldと等価である。 b)(r, 0)と等価である、sum
は、精度を最大化するために特殊なアルゴリズムを使用している、 である。- もし std.range.primitives.ElementTypeRが浮動小数点
型であり、R が
のランダムアクセス範囲である。
長さとスライスを持つランダムアクセス範囲である場合
sum
は 対和 アルゴリズムを使用する。 - ElementType!R が浮動小数点型で、R が有限の入力範囲(ただし、スライシングを伴うランダムアクセス範囲ではない)である場合、ペアワイズサムアルゴリズムを使用する。
有限の入力範囲(ただし、スライシングを伴うランダムアクセス範囲ではない)である場合、次のようになる。
sum
はKahan和アルゴリズムを使用する。 - それ以外の場合は、単純な要素ごとの加算が行われる。
sum
.に渡すことができる。 このシードは初期値として使われるだけでなく、その型が上記をすべて上書きし、和のアルゴリズムと精度を決定する。 を決定する。シードが渡されない場合、シードは の値で作成される。 typeof(r
.front +r
.front)(0)または typeof(r
.front +r
.front).zero の値で作成される。 これらの特殊化された和算アルゴリズムは、通常の和算よりも多くのプリミティブな演算を実行することに注意されたい。 を実行することに注意されたい。したがって、精度を犠牲にしてでも最高速度が必要な場合は を使うことができる。 fold!((a, b) => a + b)(r
, 0)を使うことができる。 を使うことができる。Parameters:E seed
和の初期値 R r
有限の入力範囲 Returns:rの範囲にあるすべての要素の和。Examples:同上import std.range; //単純な積分和 writeln(sum([1, 2, 3, 4])); // 10 //積分促進を使う writeln(sum([false, true, true, false, true])); // 3 writeln(sum(ubyte.max.repeat(100))); // 25500 //結果がオーバーフローする可能性がある writeln(uint.max.repeat(3).sum()); // 4294967293U //しかし、シードを使って和プリミティブを変更することができる writeln(uint.max.repeat(3).sum(ulong.init)); // 12884901885UL //浮動小数点和 writeln(sum([1.0, 2.0, 3.0, 4.0])); // 10 //浮動小数点演算には倍精度最小値がある static assert(is(typeof(sum([1F, 2F, 3F, 4F])) == double)); writeln(sum([1F, 2, 3, 4])); // 10 //大きな整数に対してペアごとの浮動小数点和を強制する import std.math.operations : isClose; assert(iota(ulong.max / 2, ulong.max / 2 + 4096).sum(0.0) .isClose((ulong.max / 2) * 4096.0 + 4096^^2 / 2));
- もし std.range.primitives.ElementTypeRが浮動小数点
型であり、R が
のランダムアクセス範囲である。
長さとスライスを持つランダムアクセス範囲である場合
- T
mean
(T = double, R)(Rr
)
if (isInputRange!R && isNumeric!(ElementType!R) && !isInfinite!R);
automean
(R, T)(Rr
, Tseed
)
if (isInputRange!R && !isNumeric!(ElementType!R) && is(typeof(r
.front +seed
)) && is(typeof(r
.front / size_t(1))) && !isInfinite!R); - 範囲の平均(俗に平均と呼ばれる)を求める。組み込みの数値型では、正確な Knuth & Welford 平均計算が使用される。 が使用される。ユーザー定義型では、要素ごとの合計が使用される。 さらに
seed
が必要である。 0 と等価である。 この関数の最初のオーバーロードは、範囲が空の場合、T.init を返す。 を返す。しかし、2番目のオーバーロードはseed
を返す。 この関数はΟ(r.length)である。Parameters:T 戻り値の型。 R r
入力範囲 T seed
ユーザー定義型の場合。0 と等価でなければならない。 Returns:の平均はr
が空でないときr
の平均は空でない。Examples:import std.math.operations : isClose; import std.math.traits : isNaN; static immutable arr1 = [1, 2, 3]; static immutable arr2 = [1.5, 2.5, 12.5]; assert(arr1.mean.isClose(2)); assert(arr2.mean.isClose(5.5)); assert(arr1[0 .. 0].mean.isNaN);
- auto
uniq
(alias pred = "a == b", Range)(Ranger
)
if (isInputRange!Range && is(typeof(binaryFun!pred(r
.front,r
.front)) == bool)); - 与えられた範囲の一意な連続する要素をのんびりと反復処理する。 ソートされていると仮定する。 uniqシステム ユーティリティに似た機能)。要素の等価性は、述語 predデフォルトでは"a == b" である。この述語は std.functional.binaryFunに渡され、文字列か、 を介して実行可能な任意の callable に渡され、文字列を受け取るか、pred(element, element) を介して実行できる任意の callable を受け取ることができる。与えられた範囲が 双方向である、
uniq
もまた を返す。Parameters:pred 範囲要素間の等価性を決定する述語。 Range r
入力範囲 要素の入力範囲。 Returns:入力範囲 連続する一意な要素の入力範囲。もしr
が も前方範囲または双方向範囲である場合、返される範囲も同様になる。Examples:import std.algorithm.comparison : equal; import std.algorithm.mutation : copy; int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ][])); // コピーを使用して重複をインプレースでフィルタリングする arr.length -= arr.uniq().copy(arr).length; writeln(arr); // [1, 2, 3, 4, 5] // 一意性が連続してのみ決定されることに注意; 異なる要素を // 挟んで重複する要素は // 削除されない: assert(equal(uniq([ 1, 1, 2, 1, 1, 3, 1]), [1, 2, 1, 3, 1]));
- Permutations!Range
permutations
(Range)(Ranger
);
structPermutations
(Range); - のすべての順列をヒープ・アルゴリズムを使ってのんびりと計算する。
r
を計算する。Parameters:Range 範囲型 Range r
ランダムアクセス範囲 の順列を見つける。 Returns:See Also:Examples:import std.algorithm.comparison : equal; import std.range : iota; assert(equal!equal(iota(3).permutations, [[0, 1, 2], [1, 0, 2], [2, 0, 1], [0, 2, 1], [1, 2, 0], [2, 1, 0]]));
Copyright © 1999-2024 by the D Language Foundation
DEEPL APIにより翻訳、ところどころ修正。
このページの最新版(英語)
このページの原文(英語)
翻訳時のdmdのバージョン: 2.108.0
ドキュメントのdmdのバージョン: 2.109.1
翻訳日付 :
HTML生成日時:
編集者: dokutoku