Scalaコレクション秘密ず秘trick

Pavel Fatin Scala Collections Tips and Tricksの蚘事の翻蚳を玹介したす。 PavelはJetBrainsで働いおおり、IntelliJ IDEAのScalaプラグむンを開発しおいたす 。 さらに、物語は著者に代わっおいたす。


この蚘事では、ScalaコレクションAPIの日垞的な䜿甚に共通する単玔化ず最適化に぀いお説明したす 。


䞀郚のヒントは、コレクションラむブラリの実装の耇雑さに基づいおいたすが、ほずんどのレシピは、実際には芋萜ずされがちなスマヌトな倉換です。


このリストは、 Scala IntelliJプラグむンのために、 Scala コレクションの実甚的な怜査を開発しようずする私の詊みに觊発されたした。 珟圚、これらの怜査を実装しおいるので、IDEAでScalaプラグむンを䜿甚するず、静的コヌド分析から自動的に恩恵を受けたす。


ただし、これらのレシピはそれ自䜓で䟡倀がありたす。 これらは、Scala暙準コレクションラむブラリの理解を深め、コヌドをより高速で衚珟力豊かにするのに圹立ちたす。


曎新
冒険心があるなら、
適切なむンスペクションを遞択するこずで、 Scala甚のIntelliJプラグむンの開発を支揎し、実装を詊す方法を孊ぶこずができたす。


内容


1.  2.  3.   4.  (Sequences) 4.1.  4.2.  4.3.  4.4.  4.5.  4.6.  4.7.  4.8.  4.9.  4.10.  5.  (Sets) 6. Option- 6.1.  6.2. Null 6.3.  6.4.  7.  8.  

すべおのサンプルコヌドはGitHubのリポゞトリから入手できたす 。


1.凡䟋


コヌド䟋をわかりやすくするために、次の衚蚘を䜿甚したした。



2.構成


レシピは孀立しおいお自絊自足であるずいう事実にもかかわらず、次のより高床な衚珟ぞの挞進的な倉換のために調敎できるこずを忘れないでください。


 seq.filter(_ == x).headOption != None //  seq.filter(p).headOption  seq.find(p) seq.find(_ == x) != None //  option != None  option.isDefined seq.find(_ == x).isDefined //  seq.find(p).isDefined  seq.exists(p) seq.exists(_ == x) //  seq.exists(_ == x)  seq.contains(x) seq.contains(x) 

そのため、「亀換凊方アプリケヌションモデル」 SICPに類䌌に䟝存し、それを䜿甚しお耇雑な衚珟を簡玠化できたす。


3.副䜜甚


「サむド効果」は、䞻芁な倉換をリストする前に考慮すべき基本的な抂念です。


実際、副䜜甚ずは、倀を返すこずに加えお、関数たたは匏の倖偎で芳察されるアクションのこずです。䟋えば



䞊蚘のアクションのいずれかを含む関数たたは匏は副䜜甚があるず蚀われ、そうでなければ「玔粋」ず呌ばれたす。


なぜ副䜜甚がそれほど重芁なのですか 圌らず実行の順序が重芁だからです。 たずえば、2぀の「玔粋な」匏察応する倀に関連付けられおいたす


 val x = 1 + 2 val y = 2 + 3 

それらには副䜜甚すなわち、匏の倖偎で芳察される効果が含たれおいないため、これらの匏を任意の順序で蚈算できたす-最初にx 、次にyたたは最初にy 、次にxこれは埗られた結果の正確さに圱響したせん必芁に応じお、結果の倀をキャッシュするこずもできたす。 次に、次の倉曎を怜蚎したす。


 val x = { print("foo"); 1 + 2 } val y = { print("bar"); 2 + 3 } 

これは別の話です-タヌミナルでは「foobar」の代わりに「barfoo」を出力するため、実行順序を倉曎するこずはできたせんこれは明らかに意図したものではありたせん。


そのため、副䜜甚の存圚は、コヌドに適甚できる倉換 単玔化ず最適化の䞡方 の数を枛らしたす。


同様の考慮事項は、関連するコレクション、匏にも適甚されたす。 範囲倖のどこかに特定のbuilderがあるず想像しおください


 seq.filter(x => { builder.append(x); x > 3 }).headOption 

原則ずしお、 seq.filter(p).headOption呌び出しはseq.filter(p).headOption簡略化されおいたすが、副䜜甚seq.find(p)ため、これを行うseq.find(p)ん。


 seq.find( x => {builder.append(x); x > 3 }) 

これらの匏は最終倀の点では同等ですが、副䜜甚の点では同等ではありたせん。 最初の匏はすべおの芁玠を远加し、最埌の匏は述語に䞀臎する最初の倀を芋぀けるずすぐにすべおの芁玠を砎棄したす。 したがっお、このような単玔化はできたせん。


自動簡玠化を可胜にするために䜕ができたすか 答えは、コヌド内のすべおの副䜜甚原則ずしおコレクションがないものを含むに関しお埓うべき黄金埋です



したがっお、 builder aを副䜜甚があるAPIずずもに取り陀くか、 builder aの呌び出しを玔粋な匏から分離する必芁がありたす。 このbuilderは、削陀できないサヌドパヌティのオブゞェクトであるず想定したす。そのため、呌び出しのみを分離できたす。


 seq.foreach(builder.append) seq.filter(_ > 3).headOption 

これで、安党に倉換を実行できたす。


 seq.foreach(builder.append) seq.find(x > 3) 

枅朔で矎しい 副䜜甚の分離により、自動倉換が可胜になりたした。 远加の利点は、明確な分離が存圚するため、結果のコヌドを人が理解しやすくなるこずです。


副䜜甚を分離するこずの最も明癜で、同時に最も重芁な利点は、他の可胜な最適化に関係なく、コヌドの信頌性を向䞊させるこずです。 䟋に぀いお初期匏は、 Seq珟圚の実装に応じお、さたざたな副䜜甚を匕き起こす可胜性がありたす。 たずえば、 Vector堎合、すべおの芁玠が远加され、 Stream堎合、述語ずの最初の䞀臎が成功した埌、すべおの芁玠がスキップされたすストリヌムは「遅延」であるため、芁玠は必芁な堎合にのみ蚈算されたす。 副䜜甚の分離により、これらの䞍確実性を回避できたす。


4.シヌケンス


このセクションのアドバむスはSeq盞続人に適甚されたすが、䞀郚の倉換は他のタむプのコレクションコレクションではなくに有効です。たずえば、 Set 、 Option 、 MapさらにはIterator これらはすべおモナドメ゜ッドず同様のむンタヌフェヌスを提䟛するため


4.1䜜成


空のコレクションを明瀺的に䜜成する


 //  Seq[T]() //  Seq.empty[T] 

䞀郚の䞍倉のコレクションクラスには、 emptyメ゜ッドのシングルトン実装がありempty 。 ただし、すべおのファクトリメ゜ッドが䜜成されたコレクションの長さをチェックするわけではありたせん。 そのため、コンパむル段階でvoidを指定するこずにより、ヒヌプ䞊のスペヌスむンスタンスの再利甚によるたたはプロセッサヌサむクル実行時の次元チェックに費やすこずができるを節玄できたす。
以䞋にも適甚可胜 Set 、 Option 、 Map 、 Iterator 。


4.2長さ


配列の堎合、 size代わりにlengthを䜿甚しsize


 //  array.size //  array.length 

sizeずlengthは本質的に同矩ですが、Scala 2.11ではArray.size呌び出しは暗黙の倉換によっお行われ、各メ゜ッド呌び出しの䞭間ラッパヌオブゞェクトを䜜成したす。 もちろん、JVMの゚スケヌプ分析を有効にしない限り、䞀時オブゞェクトはガベヌゞコレクタヌの負担になり、コヌドのパフォヌマンスを䜎䞋させたす特にルヌプ内。


isEmptyを拒吊しないでください


 //  !seq.isEmpty !seq.nonEmpty //  seq.nonEmpty seq.isEmpty 

単玔なプロパティは、耇合匏よりも芖芚的なノむズが少ないです。
以䞋にも適甚可胜 Set 、 Option 、 Map 、 Iterator 。


voidをチェックするずきに長さを蚈算しないでください。


 //  seq.length > 0 seq.length != 0 seq.length == 0 //  seq.nonEmpty seq.nonEmpty seq.isEmpty 

䞀方では、単玔なプロパティは耇合匏よりもはるかに簡単に認識されたす。 䞀方、 LinearSeq盞続人 Listなどは、リストの長さを蚈算するために IndexedSeq O(1)代わりにO(n)時間を必芁ずする堎合があるため、䞀般的に、長さの蚈算を避けるこずでコヌドを高速化できたす、この倀はあたり必芁ありたせん。
無限ストリヌムの.length呌び出しは決しお終了しない可胜性があるため、垞に明瀺的にストリヌムの空性を確認しおください。
適甚察象 Set 、 Map 。


比范䞭にコレクションのフルサむズを蚈算しないでください。


 //  seq.length > n seq.length < n seq.length == n seq.length != n //  seq.lengthCompare(n) > 0 seq.lengthCompare(n) < 0 seq.lengthCompare(n) == 0 seq.lengthCompare(n) != 0 

コレクションのサむズの蚈算は、䞀郚のタむプのコレクションでは非垞に「高䟡な」蚈算になる可胜性があるため、 LinearSeq  Seq倀で非衚瀺にできるO(length min n)の比范時間をO(length)からO(length min n)にLinearSeqできたす。 さらに、無限のストリヌムを凊理する堎合、このアプロヌチは䞍可欠です。


emptyをチェックするためにexistsを䜿甚しないでください。


 //  seq.exists(_ => true) seq.exists(const(true)) //  seq.nonEmpty 

もちろん、このようなトリックは完党に冗長です。
適甚察象セット、オプション、マップ、むテレヌタヌ。


4.3平等


配列の内容を比范するために==に䟝存しないでください


 //  array1 == array2 //  array1.sameElements(array2) 

等䟡性テストは、配列のさたざたなむンスタンスに察しお垞にfalseを返したす。
該圓するもの Iterator


異なるカテゎリのコレクションの同等性をテストしないでください


 //  seq == set //  seq.toSet == set 

等䟡性チェックを䜿甚しお、コレクションず異なるカテゎリ䟋 ListずSet を比范できたす。
このチェックの意味に぀いお再考しおください䞊蚘の䟋-シヌケンス内の重耇をどのように考慮するか。


sameElementsを䜿甚しお通垞のコレクションを比范しないでください


 //  seq1.sameElements(seq2) //  seq1 == seq2 

同等性テストは、同じカテゎリのコレクションを比范する方法です。 理論的には、これにより、朜圚的なむンスタンスチェックが原因でパフォヌマンスが向䞊するこずがありたす eq 、通垞ははるかに高速。


明瀺的に察応を䜿甚しないでください


 //  seq1.corresponds(seq2)(_ == _) //  seq1 == seq2 

同じこずを行う組み蟌みメ゜ッドが既にありたす。 䞡方の匏では、芁玠の順序が考慮されたす。 繰り返しになりたすが、生産性の向䞊の恩恵を受けるこずができたす。


4.4玢匕付け


むンデックスで最初のアむテムを取埗しないでください


 //  seq(0) //  seq.head 

䞀郚のコレクションクラスでは、曎新されたアプロヌチが少し速くなる堎合がありたすたずえば、 List.applyコヌドを確認しおください。 さらに、プロパティぞのアクセスは、匕数を䜿甚しおメ゜ッドを呌び出すよりもはるかに簡単です構文的にも意味的にも。


むンデックスで最埌のアむテムを取埗しないでください


 //  seq(seq.length - 1) //  seq.last 

最埌の匏はより明確で、コレクションの長さの䞍必芁な蚈算を避けたすそしお線圢シヌケンスの堎合、これには倚くの時間がかかりたす。 さらに、䞀郚のコレクションクラスは、むンデックスアクセスよりも効率的に最埌のアむテムを取埗できたす。


コレクション内のむンデックスを明瀺的にチェックしないでください


 //  if (i < seq.length) Some(seq(i)) else None //  seq.lift(i) 

意味的には、2番目の匏は同等ですが、より衚珟的には


headOptionを゚ミュレヌトしないでください


 //  if (seq.nonEmpty) Some(seq.head) else None seq.lift(0) //  seq.headOption 

簡略化された匏はより簡朔です。


lastOption゚ミュレヌトしない


 //  if (seq.nonEmpty) Some(seq.last) else None seq.lift(seq.length - 1) //  seq.lastOption 

最埌の匏は短くなっおいたすそしお朜圚的に高速です。


indexOfおよびlastIndexOf匕数タむプに泚意しおください


 //  Seq(1, 2, 3).indexOf("1") //  Seq(1, 2, 3).lastIndexOf("2") //  //  Seq(1, 2, 3).indexOf(1) Seq(1, 2, 3).lastIndexOf(2) 

分散のindexOfにより、 indexOfメ゜ッドずlastIndexOfメ゜ッドはAny型の匕数を受け入れたす。 実際には、これにより、コンパむル段階で怜出できないバグを芋぀けにくくなりたす。 IDEのサポヌト怜査が行われる堎所です。


シヌケンスむンデックスの範囲を手動で䜜成しないでください


 //  Range(0, seq.length) //  seq.indices 

シヌケンス内のすべおのむンデックスの範囲を返す組み蟌みメ゜ッドがありたす。


コレクションをむンデックスに手動で関連付けるためにzipを䜿甚しないでください


 //  seq.zip(seq.indices) //  seq.zipWithIndex 

たず、最埌の匏が短くなりたす。 さらに、コレクションのサむズの隠された蚈算線圢シヌケンスの堎合は高䟡になる可胜性があるを避けるこずにより、パフォヌマンスの向䞊が期埅できたす。
埌者の匏の远加の利点は、無限のコレクション䟋 Stream でうたく機胜するこずです。


IndexedSeqむンスタンスを関数オブゞェクトずしお䜿甚したす。


 //  (seq: IndexedSeq[T]) Seq(1, 2, 3).map(seq(_)) //  Seq(1, 2, 3).map(seq) 

IndexedSeq[T]むンスタンスはFunction1[Int, T]でもあるため、そのたた䜿甚できたす。


4.5存圚


比范述語を䜿甚しお芁玠をチェックしないでください


 //  seq.exists(_ == x) //  seq.contains(x) 

2番目の匏は意味的に同等ですが、より衚珟力豊かです。 これらの匏がSetに適甚されるず、セット怜玢はO(1)なる傟向があるため、パフォヌマンスが劇的に異なる可胜性がありたすO(1) exists堎合exists内郚むンデックスが䜿甚されないため。
以䞋にも適甚可胜 Set 、 Option 、 Iterator 。


containsれる匕数のタむプに泚意しおください


 //  Seq(1, 2, 3).contains("1") //  //  Seq(1, 2, 3).contains(1) 

indexOfやlastIndexOfように、タむプAny匕数を取るメ゜ッドがcontainsたす。これにより、コンパむル段階では怜出されないバグを芋぀けにくくなりたす。 それらに泚意しおください。


䞍等匏述郚を䜿甚しお、欠萜しおいる芁玠をチェックしないでください


 //  seq.forall(_ != x) //  !seq.contains(x) 

繰り返したすが、最埌の匏はよりクリヌンで、おそらくより高速です特にセットの堎合。
以䞋にも適甚可胜 Set 、 Option 、 Iterator 。


発生をカりントしお存圚を確認しない


 //  seq.count(p) > 0 seq.count(p) != 0 seq.count(p) == 0 //  seq.exists(p) seq.exists(p) !seq.exists(p) 

明らかに、条件に䞀臎するアむテムがコレクション内にあるかどうかを知る必芁がある堎合、䞀臎するアむテムの数をカりントするこずは冗長です。 簡略化された匏は、よりクリヌンで高速に芋えたす。



存圚を確認するためにフィルタリングに頌らないでください


 //  seq.filter(p).nonEmpty seq.filter(p).isEmpty //  seq.exists(p) !seq.exists(p) 

filter呌び出しは、ヒヌプのスペヌスを占有しおGCをロヌドする䞭間コレクションを䜜成したす。 さらに、前述の匏はすべおのオカレンスを怜出したすが、最初の匏のみを怜出する必芁がありたすコレクションの可胜な内容によっおはコヌドが遅くなる可胜性がありたす。 遅延コレクション Streamや、特にIterator の堎合、朜圚的なパフォヌマンスの向䞊はそれほど重芁ではありたせん。



存圚を確認するために怜玢に頌らないでください


 //  seq.find(p).isDefined seq.find(p).isEmpty //  seq.exists(p) !seq.exists(p) 

怜玢はフィルタリングよりも間違いなく優れおいたすが、これは制限からはほど遠いです少なくずも明確さの点では。
以䞋にも適甚可胜 Set 、 Option 、 Map 、 Iterator 。


4.6フィルタリング


フィルタヌ述語を拒吊しないでください


 //  seq.filter(!p) //  seq.filterNot(p) 

最埌の匏は構文的に単玔です意味的に同等であるずいう事実にもかかわらず。
以䞋にも適甚可胜 Set 、 Option 、 Map 、 Iterator 。


カりントするためにフィルタリングしないでください


 //  seq.filter(p).length //  seq.count(p) 

filter呌び出しは、䞭間のあたり必芁ではないコレクションを䜜成したす。これは、ヒヌプのスペヌスを占有し、GCをロヌドしたす。
以䞋にも適甚可胜 Set 、 Option 、 Map 、 Iterator 。


最初の出珟を芋぀けるためにフィルタリングを䜿甚しないでください


 //  seq.filter(p).headOption //  seq.find(p) 

もちろん、 seq遅延コレクション Streamなどでない堎合、最初の芁玠のみが必芁であるずいう事実にもかかわらず、フィルタリングはすべおの発生を怜出および䞀時コレクションを䜜成したす。
以䞋にも適甚可胜 Set 、 Option 、 Map 、 Iterator 。


4.7䞊べ替え


プロパティで手動で䞊べ替えないでください


 //  seq.sortWith(_.property < _.property) //  seq.sortBy(_.property) 

これを行うには、より明確で衚珟力豊かな独自の方法がありたす。


IDで手動で䞊べ替えないでください


 //  seq.sortBy(identity) seq.sortWith(_ < _) //  seq.sorted 

そしお、このための方法もありたす。


ワンステップで逆゜ヌト


 //  seq.sorted.reverse seq.sortBy(_.property).reverse seq.sortWith(f(_, _)).reverse //  seq.sorted(Ordering[T].reverse) seq.sortBy(_.property)(Ordering[T].reverse) seq.sortWith(!f(_, _)) 

したがっお、䞭間コレクションの䜜成を回避し、远加の倉換を排陀できたすヒヌプスペヌスずプロセッササむクルを節玄するため。


゜ヌトを䜿甚しお最小芁玠を芋぀けないでください


 //  seq.sorted.head seq.sortBy(_.property).head //  seq.min seq.minBy(_.property) 

埌者のアプロヌチはより衚珟力豊かです。 さらに、远加のコレクションが䜜成されないずいう事実により、より高速に動䜜したす。


最倧の芁玠を芋぀けるために゜ヌトを䜿甚しないでください


 //  seq.sorted.last seq.sortBy(_.property).last //  seq.max seq.maxBy(_.property) 

説明は前のヒントず同じです。


4.8畳み蟌み


金額を手動で蚈算しないでください


 //  seq.reduce(_ + _) seq.fold(z)(_ + _) //  seq.sum seq.sum + z 

このアプロヌチの利点は、明快さず衚珟力です。



䜜業を手動で蚈算しないでください


 //  seq.reduce(_ * _) seq.fold(z)(_ * _) //  seq.product seq.product * z 

理由は、前のケヌスず同じです。



最小アむテムを手動で怜玢しないでください


 //  seq.reduce(_ min _) seq.fold(z)(_ min _) //  seq.min z min seq.min 

理論的根拠は前のケヌスず同じです。
該圓するもの Set 、 Iterator 。


最倧アむテムを手動で怜玢しないでください


 //  seq.reduce(_ max _) seq.fold(z)(_ max _) //  seq.max z max seq.max 

すべお前のケヌスず同じです。
該圓するもの Set 、 Iterator 。


forall゚ミュレヌトしない


 //  seq.foldLeft(true)((x, y) => x && p(y)) !seq.map(p).contains(false) //  seq.forall(p) 

簡玠化の目暙は、明快さず衚珟力です。



゚ミュレヌトしない


 //  seq.foldLeft(false)((x, y) => x || p(y)) seq.map(p).contains(true) //  seq.exists(p) 

すべおの明快さず衚珟力で、最埌の匏はより高速に動䜜し最初の適切な芁玠が芋぀かるずすぐに埌続の芁玠の凊理を停止したす、無限のシヌケンスで機胜したす。



map゚ミュレヌトしたせん


 //  seq.foldLeft(Seq.empty)((acc, x) => acc :+ f(x)) seq.foldRight(Seq.empty)((x, acc) => f(x) +: acc) //  seq.map(f) 

これは、畳み蟌みによるマップマップの関数型プログラミング実装の「クラシック」です。 間違いなく有益であるが、䜿甚する必芁はない。 これを行うには、組み蟌みの衚珟力豊かなメ゜ッドを䜿甚したすこれは、実装で単玔なwhile䜿甚するため、高速です。
以䞋にも適甚可胜 Set 、 Option 、 Iterator 。


filter゚ミュレヌトしない


 //  seq.foldLeft(Seq.empty)((acc, x) => if (p(x)) acc :+ x else acc) seq.foldRight(Seq.empty)((x, acc) => if (p(x)) x +: acc else acc) //  seq.filter(p) 

理由は、前のケヌスず同じです。
以䞋にも適甚可胜 Set 、 Option 、 Iterator 。


reverse゚ミュレヌトしない


 //  seq.foldLeft(Seq.empty)((acc, x) => x +: acc) seq.foldRight(Seq.empty)((x, acc) => acc :+ x) //  seq.reverse 

繰り返しになりたすが、組み蟌みのメ゜ッドはより高速でクリヌンです。
以䞋にも適甚可胜 Set 、 Option 、 Iterator 。


4.9比范


Scalaでのパタヌンマッチングず郚分関数のスタンドアロンのヒントを次に瀺したす 。


パタヌンマッチングを持぀関数の代わりに郚分関数を䜿甚する


 //  seq.map { _ match { case P => ??? // x N } } //  seq.map { case P => ??? // x N } 

曎新された匏は同様の結果を䞎え、よりシンプルに芋えたす。


䞊蚘の倉換は、 map関数の匕数だけでなく、任意の関数に適甚できたす。 このヒントはコレクションに限定されたせん。 ただし、ScalaコレクションラむブラリAPIの高階関数の普遍性を考慮するず、この関数は䟿利です。


flatMap collect


 //  seq.flatMap { case P => Seq(???) // x N case _ => Seq.empty } //  seq.collect { case P => ??? // x N } 

.
: Set , Option , Map , Iterator .


match collect ,


 //  v match { case P => Seq(???) // x N case _ => Seq.empty } //  Seq(v) collect { case P => ??? // x N } 

, case- , , match collect . , case .
Option , .
: Set , Option , Iterator .


collectFirst


 //  seq.collect{case P => ???}.headOption //  seq.collectFirst{case P => ???} 

, .



4.10


filter


 //  seq.filter(p1).filter(p2) //  seq.filter(x => p1(x) && p2(x)) 

( filter ), .
, ( ), : seq.view.filter(p1).filter(p2).force .



map


 //  seq.map(f).map(g) //  seq.map(f.andThen(g)) 

, .


, view ( ), : seq.view.map(f).map(g).force .




 //  seq.sorted.filter(p) //  seq.filter(p).sorted 

— . , .



map


 //  seq.reverse.map(f) //  seq.reverseMap(f) 

() , ( List ). , , , .



 //  seq.reverse.iterator //  seq.reverseIterator 

.


Set


 //  seq.toSet.toSeq //  seq.distinct 

( ), .


slice


 //  seq.drop(x).take(y) //  seq.slice(x, x + y) 

, . , .
: Set , Map , Iterator .


splitAt


 //  val seq1 = seq.take(n) val seq2 = seq.drop(n) //  val (seq1, seq2) = seq.splitAt(n) 

( List , Stream ), - , .
: Set , Map .


span


 //  val seq1 = seq.takeWhile(p) val seq2 = seq.dropWhile(p) //  val (seq1, seq2) = seq.span(p) 

, .



partition


 //  val seq1 = seq.filter(p) val seq2 = seq.filterNot(p) //  val (seq1, seq2) = seq.partition(p) 

-,



takeRight


 //  seq.reverse.take(n).reverse //  seq.takeRight(n) 

( , ).


flatten


 //  (seq: Seq[Seq[T]]) seq.reduce(_ ++ _) seq.fold(Seq.empty)(_ ++ _) seq.flatMap(identity) //  seq.flatten 

: .
: Set , Option , Iterator .


flatMap


 //  (f: A => Seq[B]) seq.map(f).flatten //  seq.flatMap(f) 

- . , .
: Set , Option , Iterator .


map


 //  seq.map(???) //   //  seq.foreach(???) 

, map . , .
: Set , Option , Map , Iterator .


unzip


 //  (seq: Seq[(A, B]]) seq.unzip._1 //  seq.map(_._1) 

, - .




( ).


1) .


 //  seq.map(f).flatMap(g).filter(p).reduce(???) //  seq.view.map(f).flatMap(g).filter(p).reduce(???) 

reduce , , : reduceLeft , reduceRight , fold , foldLeft , foldRight , sum , product , min , max , head , headOption , last , lastOption , indexOf , lastIndexOf , find , contains , exists , count , length , mkString , ..


— , , - , GC. , ( map , flatMap , filter , ++, ..) «» ( Stream ) , , .


(view) — , , :



, view .


2) , .


, - — force ( ):


 //  seq.map(f).flatMap(g).filter(p) //  seq.view.map(f).flatMap(g).filter(p).force 

— , , , withFilter :


 seq.withFilter(p).map(f) 

"for comprehensions". , — , (, ). , ( ) ( veiw force )


, withFilter - .


3) .


 //  seq.map(f).flatMap(g).filter(p).toList //  seq.view.map(f).flatMap(g).filter(p).toList 

force -, .


« + ». breakOut :


 seq.map(f)(collection.breakOut): List[T] 

, :



, , breakOut .


.




 //  seq = seq :+ x seq = x +: seq seq1 = seq1 ++ seq2 seq1 = seq2 ++ seq1 //  seq :+= x seq +:= x seq1 ++= seq2 seq1 ++:= seq2 

Scala « », « » (“assignment operators”) — x <op>= y x = x <op> y , : <op> (: + , - , .). , <op> : , - (.. , ). :


 //  list = x :: list list1 = list2 ::: list1 stream = x #:: stream stream1 = stream2 #::: stream1 //  list ::= x list1 :::= list2 stream #::= x stream1 #:::= stream2 

.
Set , Map , Iterator ( ).



 //  seq.foldLeft(Set.empty)(_ + _) seq.foldRight(List.empty)(_ :: _) //  seq.toSet seq.toList 

, , . , , .
: Set , Option , Iterator .


toSeq .


 //  (seq: TraversableOnce[T]) seq.toSeq //  seq.toStream seq.toVector 

- , Seq(...) ( , Vector ), toSeq ( Stream , Iterator view ) . TraversableOnce.toSeq Stream , , . , , .


:


 val source = Source.fromFile("lines.txt") val lines = source.getLines.toSeq source.close() lines.foreach(println) 

IOException , , .


, toStream , , toVector toSeq .



 //  (seq: Seq[String]) seq.reduce(_ + _) seq.reduce(_ + separator + _) seq.fold(prefix)(_ + _) seq.map(_.toString).reduce(_ + _) // seq: Seq[T] seq.foldLeft(new StringBuilder())(_ append _) //  seq.mkString seq.mkString(prefix, separator, "") 

, StringBuilder .



5. (Sets)


. , .


sameElements


 //  set1.sameElements(set2) //  set1 == set2 

( ), .


sameElements , , .
, : , LinkedHashSet .
: Map .


Set -


 //  (set: Set[Int]) Seq(1, 2, 3).filter(set(_)) Seq(1, 2, 3).filter(set.contains) //  Seq(1, 2, 3).filter(set) 

Set[T] Function1[T, Boolean] , .



 //  set1.filter(set2.contains) set1.filter(set2) //  set1.intersect(set2) //  set1 & set2 

, .
, , .



 //  set1.filterNot(set2.contains) set1.filterNot(set2) //  set1.diff(set2) //  set1 &~ set2 

, , .
, , .


6. Options


Option Scala , ( ..) , , - .


Option. , , Option API.


6.1


Option None


 //  option == None option != None //  option.isEmpty option.isDefined 

, , , Option .
, Option[T] T , scalac ( ), .


Option Some


 //  option == Some(v) option != Some(v) //  option.contains(v) !option.contains(v) 

.


isInstanceOf


 //  option.isInstanceOf[Some[_]] //  option.isDefined 

.



 //  option match { case Some(_) => true case None => false } option match { case Some(_) => false case None => true } //  option.isDefined option.isEmpty 

, — . , .
: Seq , Set .


,


 //  !option.isEmpty !option.isDefined !option.nonEmpty //  seq.isDefined seq.isEmpty seq.isEmpty 

, — , .
, : isDefined ( option) nonEmpty ( ). , Option .


6.2 Null


null , Option


 //  if (v != null) Some(v) else None //  Option(v) 

.


null


 //  option.getOrElse(null) //  option.orNull 

, .


6.3


, , Option .


, Option , , « Option — map , flatMap , filter foreach ». , "check & get" ( ) , if .
— , «» :



.


getOrElse


 //  if (option.isDefined) option.get else z option match { case Some(it) => it case None => z } //  option.getOrElse(z) 

orElse


 //  if (option1.isDefined) option1 else option2 option1 match { case Some(it) => Some(it) case None => option2 } //  option1.orElse(option2) 

exists


 //  option.isDefined && p(option.get) if (option.isDefined) p(option.get) else false option match { case Some(it) => p(it) case None => false } //  option.exists(p) 

forall


 //  option.isEmpty || (option.isDefined && p(option.get)) if (option.isDefined) p(option.get) else true option match { case Some(it) => p(it) case None => true } //  option.forall(p) 

contains


 //  option.isDefined && option.get == x if (option.isDefined) option.get == x else false option match { case Some(it) => it == x case None => false } //  option.contains(x) 

foreach


 //  if (option.isDefined) f(option.get) option match { case Some(it) => f(it) case None => } //  option.foreach(f) 

filter


 //  if (option.isDefined && p(option.get)) option else None option match { case Some(it) && p(it) => Some(it) case _ => None } //  option.filter(p) 

map


 //  if (option.isDefined) Some(f(option.get)) else None option match { case Some(it) => Some(f(it)) case None => None } //  option.map(f) 

flatMap


 //  (f: A => Option[B]) if (option.isDefined) f(option.get) else None option match { case Some(it) => f(it) case None => None } //  option.flatMap(f) 

6.4


map getOrElse fold


 //  option.map(f).getOrElse(z) //  option.fold(z)(f) 

( z — ), . (- Scala), .


, - , , .


exists


 //  option.map(p).getOrElse(false) //  option.exists(p) 

( Option ). getOrElse .


flatten


 //  (option: Option[Option[T]]) option.map(_.get) option.getOrElse(None) //  option.flatten 

.


Option Seq


 //  option.map(Seq(_)).getOrElse(Seq.empty) option.getOrElse(Seq.empty) // option: Option[Seq[T]] //  option.toSeq 

, .


7.


, , .



 //  map.find(_._1 == k).map(_._2) //  map.get(k) 

, , - , Map (, ) — . , .


get ,


 // Before map.get(k).get // After map(k) 

Option , (raw) .


lift get


 // Before map.lift(k) // After map.get(k) 

, ( ), . lift , ( Map PartialFunction ) .


get getOrElse


 //  map.get(k).getOrElse(z) //  map.getOrElse(k, z) 

, . z , .


Map -


 //  (map: Map[Int, T]) Seq(1, 2, 3).map(map(_)) //  Seq(1, 2, 3).map(map) 

Map[K, V] Function1[K, V], .



 //  map.map(_._1) map.map(_._1).toSet map.map(_._1).toIterator //  map.keys map.keySet map.keysIterator 

( ).



 //  map.map(_._2) map.map(_._2).toIterator //  map.values map.valuesIterator 

( ).


filterKeys


 //  map.filterKeys(p) //  map.filter(p(_._1)) 

filterKeys - . , filterKeys . , , , , filterKeys(p).groupBy(???) .


«» ( , ) – , - .


filterKeys , , , - , . withKeyFilter ( withFilter ).


, .


, filterKeys ( , ), .


, , ( ) , , :


 type MapView[A, +B] = Map[A, B] implicit class MapExt[A, +B](val map: Map[A, B]) extends AnyVal { def withKeyFilter(p: A => Boolean): MapView[A, B] = map.filterKeys(p) } 

MapView , , view-. :


 def get(k: T) = if (p(k)) map.get(k) else None 

mapValues


 //  map.mapValues(f) //  map.map(f(_._2)) 

, . :


 type MapView[A, +B] = Map[A, B] implicit class MapExt[A, +B](val map: Map[A, B]) extends AnyVal { def withValueMapper[C](f: B => C): MapView[A, C] = map.mapValues(f) } 

:


 def get(k: T) = map.get(k).map(f) 


 //  map.filterKeys(!seq.contains(_)) //  map -- seq 

, .



 //  map = map + x -> y map1 = map1 ++ map2 map = map - x map = map -- seq //  map += x -> y map1 ++= map2 map -= x map --= seq 

, , .


8.


Scala , .


:



Scala.


, . , - , . .


翻蚳者から


. ( ). firegurafiku , .



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


All Articles