玔粋なJavaScriptトランスデュヌサヌパス

いわゆる「トランスデュヌサヌ」に぀いお聞いたこずがありたすが、それでもJavaScriptの開発に䜿甚しない堎合は、今日、「トランスデュヌサヌずは」ず「䜿甚方法」ずいう質問に察する答えを芋぀ける機䌚がありたす。 これにより、プロゞェクトでそれらが必芁かどうかを理解できるようになり、必芁に応じおそれらの䜿甚を開始するのに圹立ちたす。



それは、あたり倚くのメモリを消費せずにパむプラむンをリンクするのに適したデヌタ倉換を構築するように蚭蚈されたコヌドをどのように曞くかに぀いおです。 トランスデュヌサの抂念を適切に理解するために、デヌタを折り畳むための単玔なメカニズム、枛速機、たたは機胜から始めたす。

枛速機


レデュヌサヌは、ストレヌゞオブゞェクトず特定のオブゞェクト芁玠を入力ずしお受け入れ、この芁玠をドラむブに配眮する機胜です。 たずえば、レデュヌサヌは次のずおりです。

(acc, val) => acc.concat([val]) 。 転送されたドラむブが配列[1, 2, 3]で、芁玠が数字4堎合、配列[1, 2, 3, 4]を返したす。

 const acc = [1, 2, 3]; const val = 4; const reducer = (acc, val) => acc.concat([val]); reducer(acc, val) ///=> 1, 2, 3, 4 

この堎合、リデュヌサヌは、枡された芁玠のリストずナニット芁玠を連結した結果を返したす。

同様の別のレデュヌサヌがありたす (acc, val) => acc.add(val) 。 このオブゞェクトを返す.add()メ゜ッドを持぀オブゞェクトに適しおいたす Set.prototype.addなど 。 レデュヌサヌは、メ゜ッドを䜿甚しお、枡された芁玠をドラむブに远加したす。 add()ドラむブをadd()たす。

 const acc = new Set([1, 2, 3]); const val = 4; const reducer = (acc, val) => acc.add(val); reducer(acc, val) ///=> Set{1, 2, 3, 4} 

連結レデュヌサヌを䜿甚しお反埩可胜なオブゞェクトから配列を䜜成する関数を次に瀺したす。

 const toArray = iterable => { const reducer = (acc, val) => acc.concat([val]); const seed = []; let accumulation = seed; for (value of iterable) {   accumulation = reducer(accumulation, value); } return accumulation; } toArray([1, 2, 3]) //=> [1, 2, 3] 

普遍的な還元関数を取埗するこずにより、 reducer倉数ずseed倉数を新しい関数のパラメヌタヌにするこずができたす考慮されたばかりの匕数ずの類䌌により、匕数iterable受け入れたす。

 const reduce = (iterable, reducer, seed) => { let accumulation = seed; for (const value of iterable) {   accumulation = reducer(accumulation, value); return accumulation; } reduce([1, 2, 3], (acc, val) => acc.concat([val]), []) //=> [1, 2, 3] 

JavaScriptは、最初のパラメヌタヌがリデュヌサヌであるreduceような関数の蚘述に関する合意に向かっお進化しおいたす。 この関数をJavaScriptAllongéスタむルで曞き換えるず、次のようになりたす。

 const reduceWith = (reducer, seed, iterable) => { let accumulation = seed; for (const value of iterable) {   accumulation = reducer(accumulation, value); } return accumulation; } reduce([1, 2, 3], (acc, val) => acc.concat([val]), []) //=> [1, 2, 3] //    : reduceWith((acc, val) => acc.concat([val]), [], [1, 2, 3]) //=> [1, 2, 3] 

JavaScriptの配列には、組み蟌みの.reduceメ゜ッドがありたす。 このメ゜ッドは、䞊蚘のreduceおよびreduceWith関数ずたったく同じように動䜜したす。

 [1, 2, 3].reduce((acc, val) => acc.concat([val]), []) //=> [1, 2, 3] 

これで、関数(acc, val) => acc.concat([val])は䞍芁なメモリ負荷を䜜成するため、次のようなリデュヌサヌに眮き換えるこずができたす。 (acc, val) => { acc.push(val); return acc; } (acc, val) => { acc.push(val); return acc; } (acc, val) => { acc.push(val); return acc; }

圢匏(acc, val) => (acc.push(val), acc)レコヌドは、セマンティックの芳点からはより良く芋えたすが、コンマ挔算子は、その䜿甚の機胜に慣れおいない人を混乱させる可胜性があるこずに泚意しおください。 これは通垞、実皌働コヌドでは避けるのが最善です。

いずれの堎合でも、芁玠を配列に収集するレデュヌサヌを取埗したす。 名前を付けお、 reduceWith関数を枡そうずしたす。

 const arrayOf = (acc, val) => { acc.push(val); return acc; }; reduceWith(arrayOf, [], [1, 2, 3]) //=> [1, 2, 3] 

別の枛速機がありたす。

 const sumOf = (acc, val) => acc + val; reduceWith(sumOf, 0, [1, 2, 3]) //=> 6 

あるタむプの反埩可胜なオブゞェクト配列などを別のタむプのオブゞェクト数倀などに瞮小するレデュヌサヌを䜜成できたす。

枛速機を食る


JavaScriptを䜿甚するず、他の関数を返す関数を簡単に䜜成できたす。 たずえば、これはレデュヌサヌを䜜成できる関数です。

 const joinedWith = separator =>   (acc, val) =>     acc == '' ? val : `${acc}${separator}${val}`; reduceWith(joinedWith(', '), '', [1, 2, 3]) //=> "1, 2, 3" reduceWith(joinedWith('.'), '', [1, 2, 3]) //=> "1.2.3" 

さらに、JSでは、他の関数を匕数ずしお取る関数を䜜成するこずは完党に自然です。

デコレヌタは、関数を匕数ずしお取り、その匕数に意味的に関連付けられおいる別の関数を返す関数です。 たずえば、この関数は、関数型プログラミングの蚀語を話す堎合、バむナリの2぀の匕数を持぀関数を取り、2番目の匕数に1を远加しお装食したす。

 const incrementSecondArgument = binaryFn =>   (x, y) => binaryFn(x, y + 1); const power = (base, exponent) => base ** exponent; const higherPower = incrementSecondArgument(power); power(2, 3) //=> 8 higherPower(2, 3) //=> 16 

この䟋では、 higherPower関数はexponent単䜍を远加するこずで修食されたexponentです。 したがっお、 higherPower(2,3)を呌び出すず、 power(2,4)ず同じ結果が埗られたす。 私たちはすでに同様の関数を䜿甚しおいたすが、レデュヌサヌもバむナリ関数です。 圌らは装食するこずができたす。

 reduceWith(incrementSecondArgument(arrayOf), [], [1, 2, 3]) //=> [2, 3, 4] const incremented = iterable =>   reduceWith(incrementSecondArgument(arrayOf), [], iterable); incremented([1, 2, 3]) //=> [2, 3, 4] 

マッピング関数


マッピング甚の関数を䜜成したした。この関数は、反埩可胜なオブゞェクトを取埗し、それぞれの倀を1぀ず぀増やしお倀を凊理した結果を返したす。 JSでプログラムを開発するずき、私たちは垞にマッピングに頌りたすが、もちろん、このメカニズムを実装する関数は通垞、芁玠が1増加する数倀配列のコピヌを䜜成するよりもわずかに倧きいず予想されたす。 incrementSecondArgument関数をもう䞀床芋おみたしょう。

 const incrementSecondArgument = binaryFn =>   (x, y) => binaryFn(x, y + 1); 

枛速機を装食するために䜿甚するため、より適切な名前を付けたす。

 const incrementValue = reducer => (acc, val) => reducer(acc, val + 1); 

これで、コヌドを読み取るずきに、 incrementValueがレデュヌサヌを匕数ずしお受け取り、枡された芁玠を凊理する前にレデュヌサヌを远加する別のレデュヌサヌを返すこずがすぐにわかりincrementValue 。 「増分」のロゞックをパラメヌタヌに入れるこずができたす。

 const map = fn =>   reducer =>     (acc, val) => reducer(acc, fn(val)); const incrementValue = map(x => x + 1); reduceWith(incrementValue(arrayOf), [], [1, 2, 3]) //=> [2, 3, 4] 

これはすべお、関数を匕数ずしお受け取り、関数を匕数ずしお受け取る他の関数を返す関数に慣れおいない人には珍しいように芋えたすが、 map(x => x + 1)構造をどこにでも配眮できたす。ここでincrementValueを䜿甚incrementValue 。 したがっお、次のように曞くこずができたす。

 reduceWith(map(x => x + 1)(arrayOf), [], [1, 2, 3]) //=> [2, 3, 4] 

たた、 mapデコレヌタは任意のレゞュヌサヌをデコレヌトできるため、数倀をむンクリメントした結果を組み合わせお文字列を圢成したり、合蚈したりするこずができたす。

 reduceWith(map(x => x + 1)(joinedWith('.')), '', [1, 2, 3]) //=> "2.3.4" reduceWith(map(x => x + 1)(sumOf), 0, [1, 2, 3]) //=> 9 

䞊蚘の手法を䜿甚しお、1から10たでの数の平方和を芋぀けおください。

 const squares = map(x => power(x, 2)); const one2ten = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; reduceWith(squares(sumOf), 0, one2ten) //=> 385 

ご芧のずおり、成功したした。 次に進みたしょう-フィルタに぀いお話したしょう。

フィルタヌ


最初の枛速機に戻りたす。

 const arrayOf = (acc, val) => { acc.push(val); return acc; }; reduceWith(arrayOf, 0, one2ten) //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

5を超える数のみを取埗する堎合はどうなりたすか 簡単に。

 const bigUns = (acc, val) => { if (val > 5 ) {   acc.push(val); } return acc; }; reduceWith(bigUns, [], one2ten) //=> [6, 7, 8, 9, 10] 

圓然のこずながら、5乗を超える数の配列を取埗するために、すでにわかっおいるすべおのものを組み合わせるこずができたす。

 reduceWith(squares(bigUns), [], one2ten) //=> [9, 16, 25, 36, 49, 64, 81, 100] 

しかし、ここで刀明したのは私たちが必芁ずするものではありたせん。 出力は、2乗が5を超える数倀ではなく、2乗が5を超える数倀です。 番号は、番号ではなく、平方する前に遞択しなければなりたせん。 システムのこの動䜜を実珟するこずはそれほど難しくありたせん。 ここでの䞀番䞋の行は、数倀のフィルタリングを担圓するデコレヌタヌが私たちを助けおくれるので、それを䜿っおレデュヌサヌを食るこずができたす。

 reduceWith(squares(arrayOf), [], one2ten) //=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] const bigUnsOf = reducer =>   (acc, val) =>     (val > 5) ? reducer(acc, val) : acc; reduceWith(bigUnsOf(squares(arrayOf)), [], one2ten) //=> [36, 49, 64, 81, 100] 

bigUnsOf関数bigUnsOf非垞に具䜓的です。 ここでは、 mapず同じこずを行いmap 。぀たり、述語関数を抜出し、それを匕数にしたす。

 reduceWith(squares(arrayOf), [], one2ten) //=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] const filter = fn =>   reducer =>     (acc, val) =>       fn(val) ? reducer(acc, val) : acc; reduceWith(filter(x => x > 5)(squares(arrayOf)), [], one2ten) //=> [36, 49, 64, 81, 100] 

もちろん、フィルタヌはどれでもかたいたせん。 それらに名前を付けお繰り返し䜿甚したり、匿名関数を䜿甚したりできたす。

 reduceWith(filter(x => x % 2 === 1)(arrayOf), [], one2ten) //=> [1, 3, 5, 7, 9] 

フィルタヌを䜿甚しお、1から10たでの奇数の平方和を芋぀けたす。

 reduceWith(filter(x => x % 2 === 1)(squares(sumOf)), 0, one2ten) //=> 165 

トランスフォヌマヌず構成


「トランスフォヌマヌ」ずいう甚語は、他のプログラミング蚀語からJavaScriptに来たした。 これは、匕数を取り、それを別のものに倉換する関数の名前です。 䞊蚘の「デコレヌタ」ず呌ばれるのは、トランスの特殊なケヌスです。 したがっお、あるリデュヌサヌを別のリデュヌサヌずする倉換関数に関する話をどこかで䌚った堎合、リデュヌサヌを「装食」する同じ機胜に぀いお話しおいるこずは明らかであり、マッピングやフィルタリングなどの远加機胜を远加したす。

先ほど説明したマッピング関数ずフィルタヌもトランスフォヌマヌです。 このプログラミングパタヌンのコンテキストでは、トランスフォヌマヌの最も重芁な特性は、構成を䜿甚しお新しいトランスフォヌマヌを䜜成するこずです。 ここでは、より明確にするために、入力時に送信された任意の2぀の関数の構成を提䟛する関数。

 const plusFive = x => x + 5; const divideByTwo = x => x / 2; plusFive(3) //=> 8 divideByTow(8) //=> 4 const compose2 = (a, b) =>   (...c) =>     a(b(...c)); const plusFiveDividedByTwo = compose2(divideByTwo, plusFive); plusFiveDividedByTwo(3) //=> 4 

トランスフォヌマヌは構成を䜿甚しお新しいトランスフォヌマヌを䜜成したす。 compose2に適甚した堎合、これはどういう意味ですか これは、圌女に任意の2぀のトランスフォヌマヌを䞎えるず、枛速機を倉換する新しいトランスフォヌマヌを取埗するこずを意味したす。 したがっお、以䞋が埗られたす。

 const squaresOfTheOddNumbers = compose2( filter(x => x % 2 === 1), squares ); reduceWith(squaresOfTheOddNumbers(sumOf), 0, one2ten) //=> 165 

squaresOfTheOddNumbersずいう名前で隠されおいるのは、 compose2関数をフィルタヌずマッピング関数に適甚するこずで䜜成したトランスフォヌマヌです。

デコレヌタを䜜成する機䌚ができたので、高床な接続性によっお区別される耇雑なコヌドを、非垞に特殊な小さなブロックに分解したす。

トランス構成


compose2関数がどのように機胜するかを知っおいるcompose2 、2぀の関数の合成を取埗できたす。任意の数の関数の合成が必芁な堎合の察凊方法を考えたす。 答えは畳み蟌みです。

compose2を曞き盎し、 compositionOfトランスフォヌマヌを䜜成したす。

 const compositionOf = (acc, val) => (...args) => val(acc(...args)); 

これで、匕数の瞮小ずしお任意の数の関数の合成を取埗するために、合成関数をcomposeできたす。

 const compose = (...fns) => reduceWith(compositionOf, x => x, fns); 

だから、私たちは最も興味深いこずになりたす。

倉換噚


次の゚ントリを怜蚎しおください。

 reduceWith(squaresOfTheOddNumbers(sumOf), 0, one2ten) 

ここでは4぀の芁玠を区別できたす。 枛速機甚のトランスフォヌマヌトランスフォヌマヌの構成、初期倀ドラむブおよび反埩可胜オブゞェクト。 トランスフォヌマヌ、レデュヌサヌ、ドラむブ、反埩可胜なオブゞェクトを別々のパラメヌタヌに入れるず、次のようになりたす。

 const transduce = (transformer, reducer, seed, iterable) => { const transformedReducer = transformer(reducer); let accumulation = seed; for (const value of iterable) {   accumulation = transformedReducer(accumulation, value); } return accumulation; } transduce(squaresOfTheOddNumbers, sumOf, 0, one2ten) //=> 165 

いく぀かのプログラミング蚀語では、倉数たたはパラメヌタヌの長い名前を枛らしたいずいう匷い芁望があるこずに泚意しおください。 その結果、かなり長い名前transformer xformたたはxf短瞮されたす。 レコヌドがxf、reduce、seed、col、たたはxf((val, acc) => acc) -> (val, acc) => accように芋える類䌌の構造を芋お驚かないでください。 ここでは省略せずに実行できたすが、生産コヌドでxform xfやxformような名前xformたったく受け入れられたす。

そしお今、実際には、それがすべお曞かれおいたこずのために。 レデュヌサヌは、 .reduce —などのメ゜ッドに枡される関数です。ストレヌゞオブゞェクトず入力デヌタを受け取り、新しいデヌタが配眮されるドラむブを返したす。 トランスフォヌマヌは、枛速機を別の枛速機に倉換する機胜です。 そしお、トランスデュヌサヌこの名前は「トランスフォヌマヌ」ず「リデュヌサヌ」ずいう甚語を組み合わせた結果です。ここでは、「レデュヌサヌずは䜕ですか」ずいう質問に察する答えです特定の倀で。

倉換噚テンプレヌトの優雅さは、トランスの構成が自然に新しいトランスの䜜成に぀ながるずいう事実にありたす。 その結果、必芁な数のトランスフォヌマヌをチェヌンできたす。 結果は1぀の倉換されたレデュヌサヌであり、反埩コレクションを1回だけ通過する必芁があるため、これは非垞に重芁です。 デヌタの䞭間コピヌを䜜成したり、それらに察しお耇数のパスを実行する必芁はありたせん。

トランスデュヌサヌは、Clojure蚀語からJavaScriptにアクセスしたしたが、ご芧のずおり、JavaScriptに完党に適合しおいるため、実装には蚀語の暙準機胜で十分です。

だから、誰かがトランスデュヌサヌずは䜕かを私たちに尋ねたら、次のように答えるこずができたす

泚このフラグメントは匷調衚瀺する必芁がありたす。

倉換噚は合成に適した倉換噚で、反埩可胜なオブゞェクトを折り畳むための枛速噚に適甚されたす。

動䜜䞭のトランスデュヌサヌ


䞊蚘では、トランスデュヌサヌの構築に぀ながるコヌド断片を調べたした。 JS゚ディタヌで既にそれらを再珟しおテストしおいる可胜性は十分にありたすが、ここでは、䟿宜䞊、わかりやすくするために、すべおのコヌドを1か所に集めおいたす。

 const arrayOf = (acc, val) => { acc.push(val); return acc; }; const sumOf = (acc, val) => acc + val; const setOf = (acc, val) => acc.add(val); const map = fn =>   reducer =>     (acc, val) => reducer(acc, fn(val)); const filter = fn =>   reducer =>     (acc, val) =>       fn(val) ? reducer(acc, val) : acc; const compose = (...fns) => fns.reduce((acc, val) => (...args) => val(acc(...args)), x => x); const transduce = (transformer, reducer, seed, iterable) => { const transformedReducer = transformer(reducer); let accumulation = seed; for (const value of iterable) {   accumulation = transformedReducer(accumulation, value); } return accumulation; } 

この䟋は、配列を操䜜するずきに通垞䜿甚されるすべおのもの、぀たり.map 、 .filter 、 .reduce 。すぐに、凊理枈みデヌタセットの耇数のコピヌの䜜成に関䞎しない構成に適したトランスデュヌサヌがありたす。 実際、実際のプロゞェクト甚に䜜成されたトランスデュヌサヌは、 .findメ゜ッドの機胜を再珟するなど、はるかに倚くのナヌス.find提䟛したす。

transduse関数transduse反埩可胜なコレクションに転送されるように蚭蚈されおいるこずに泚意しおください。さらに、初期倀ドラむブずリデュヌサヌを提䟛する必芁がありたす。 ほずんどの堎合、初期倀ずリデュヌサヌは、同じタむプのすべおのコレクションで同じ関数です。 これは、各ラむブラリにも圓おはたりたす。

オブゞェクト指向プログラミングでは、この問題はもちろん、ポリモヌフィズムによっお解決されたす。 コレクションにはメ゜ッドがあるため、適切なメ゜ッドを呌び出すこずで、必芁なものを出力ずしお取埗したす。 量産コヌドの䜜成に䜿甚されるラむブラリは、さたざたなタむプのコレクションのむンタヌフェむスを提䟛し、トランスデュヌサヌの䜿甚を䟿利にしたす。

トランスデュヌサの基瀎ずなるテンプレヌトを理解し、この蚀語が第䞀玚の機胜を提䟛する䟿利で䟿利な機胜を評䟡するには、䞊蚘で十分であるず考えおいたす。

倉換噚ナヌザヌリスト凊理


この資料では、次の問題を解決するためのオプションを瀺したす。ナヌザヌずナヌザヌが蚪れる堎所のセットがあり、どちらもハッシュコヌドのリストの圢匏で衚瀺されたす。 各行の最初のコヌドはナヌザヌ、2番目のコヌドは蚪問した堎所、たずえばレストランや店です。 リスト内のデヌタの順序が重芁です。 課題は、堎所間のどの遷移が最も人気があるかを芋぀けるこずです。

぀たり、次のようなリストがありたす。

 1a2ddc2, 5f2b932 f1a543f, 5890595 3abe124, bd11537 f1a543f, 5f2b932 f1a543f, bd11537 f1a543f, 5890595 1a2ddc2, bd11537 1a2ddc2, 5890595 3abe124, 5f2b932 f1a543f, 5f2b932 f1a543f, bd11537 f1a543f, 5890595 1a2ddc2, 5f2b932 1a2ddc2, bd11537 1a2ddc2, 5890595 ... 

このリストを泚意深く芋るず、ナヌザヌ1a2ddc2がコヌド5890595 、 5f2b932 、 bd11537 、および5890595たす。 同時に、ナヌザヌf1a543fは、堎所5890595 、 5f2b932 、 bd11537 、および5890595 。 などなど。

人々が通垞どこぞ行くのかを知る必芁があるず仮定するず、「堎所A」から「堎所B」ぞの最も人気のある遷移を芋぀ける必芁がありたす。 1a2ddc2の移動履歎は、 5f2b932 、 bd11537 、 5890595です。 これは、圌にずっお、そのような移行スキヌムを堎所から堎所ぞず構築できるこずを意味したす。

 5f2b932 -> bd11537 bd11537 -> 5890595 5890595 -> 5f2b932 5f2b932 -> bd11537 bd11537 -> 5890595 

各ナヌザヌに察しお同様のリストを䜜成する必芁があるこずに泚意しおください。 これが完了したら、最も人気のあるトランゞションを芋぀ける必芁がありたす。 同様のカりントは次のようになりたす。

遷移5f2b932 -> bd11537がリストに2回衚瀺されたす。
遷移bd11537 -> 5890595も2回発生したす。
遷移5890595 -> 5f2b932は䞀床だけ䌚った。

今やるべきこずは、すべおのナヌザヌのクリック数を蚈算し、最も人気のあるものを芋぀けるこずです。 トランスデュヌサヌを䜿甚したこの問題の解決策を次に瀺したす。

 const logContents = `1a2ddc2, 5f2b932 f1a543f, 5890595 3abe124, bd11537 f1a543f, 5f2b932 f1a543f, bd11537 f1a543f, 5890595 1a2ddc2, bd11537 1a2ddc2, 5890595 3abe124, 5f2b932 f1a543f, 5f2b932 f1a543f, bd11537 f1a543f, 5890595 1a2ddc2, 5f2b932 1a2ddc2, bd11537 1a2ddc2, 5890595`; 

 const asStream = function * (iterable) { yield * iterable; }; const lines = str => str.split('\n'); const streamOfLines = asStream(lines(logContents)); const datums = str => str.split(', '); const datumize = map(datums); const userKey = ([user, _]) => user; const pairMaker = () => { let wip = []; return reducer =>   (acc, val) => {     wip.push(val);     if (wip.length === 2) {       const pair = wip;       wip = wip.slice(1);       return reducer(acc, pair);     } else {       return acc;     } } } const sortedTransformation = (xfMaker, keyFn) => {   const decoratedReducersByKey = new Map();   return reducer =>     (acc, val) => {       const key = keyFn(val);       let decoratedReducer;       if (decoratedReducersByKey.has(key)) {         decoratedReducer = decoratedReducersByKey.get(key);       } else {         decoratedReducer = xfMaker()(reducer);         decoratedReducersByKey.set(key, decoratedReducer);       }       return decoratedReducer(acc, val);     } } const userTransitions = sortedTransformation(pairMaker, userKey); const justLocations = map(([[u1, l1], [u2, l2]]) => [l1, l2]); const stringify = map(transition => transition.join(' -> ')); const transitionKeys = compose( stringify, justLocations, userTransitions, datumize ); const countsOf = (acc, val) => {   if (acc.has(val)) {     acc.set(val, 1 + acc.get(val));   } else {     acc.set(val, 1);   }   return acc; } const greatestValue = inMap => Array.from(inMap.entries()).reduce(   ([wasKeys, wasCount], [transitionKey, count]) => {     if (count < wasCount) {       return [wasKeys, wasCount];     } else if (count > wasCount) {       return [new Set([transitionKey]), count];     } else {       wasKeys.add(transitionKey);       return [wasKeys, wasCount];     }   }   , [new Set(), 0] ); greatestValue( transduce(transitionKeys, countsOf, new Map(), streamOfLines) ) //=>   [     "5f2b932 -> bd11537",     "bd11537 -> 5890595"   ],   4 

たずめ


この資料が、誰もがトランスデュヌサヌを氞久的なツヌルにするのに圹立぀こずを願っおいたす。 圌らの研究を掘り䞋げたい堎合は、ここにトランスデュヌサヌに関する優れた資料があり、GitHubのtransdusers-jsラむブラリヌがありたす。

芪愛なる読者 JavaScriptプロゞェクトでトランスデュヌサヌを䜿甚しおいたすか

Source: https://habr.com/ru/post/J329536/


All Articles