今回はコレクションに移りましょう。 Scalaコレクション標準ライブラリは非常に豊富であるため、最も要求の厳しい開発者でさえ、既製のメソッドを提供できます。 どの場合にどの方法を適用するかは通常説明されておらず、すべてが経験から学習されます。 通常、最初は誰でも
filter
と
map
を認識し
map
、これはこれに限定できます。特定のファンタジーでは、これらの関数でのみ多くのアルゴリズムを実装できるためです。 ただし、これらの方法はドメインに対して最適ではないか、不可能な結果をもたらす可能性がありますが、処理する必要があります。
以下では、標準ライブラリのどの機能が誤って頻繁に使用され、何が改善できるかについて説明します。
foreachおよびfor(val i = 0; i <n; i ++)
Scalaに切り替えると、
for(;;)
がないために多くの人が別れます。 誰か、特にCで書いた人は、そのようなサイクルがなければプログラムを書くことはまったく不可能であり、より高度なものは外部コードの初期条件とサイクルのステップを削除し
while
アナログを書き込もうとすると考えています:
var i = 0 // var! while(i < n) { // - , i i = i+1 }
実際、
for(val i = 0; i< n; i++)
の最も正確な類似物は
for(i <- 0 until n)
、
すべてがここに表示されていましたが、すぐに表示されるとは限りません。 正しく記述するには、Rangeクラスの操作を理解し、 Code Commitなどのブログでの使用例を参照する必要があります。
イテレータ
多くの場合、古いJavaコードで作業する場合、通常は反復できないクラスが到着します。
java.sql.ResultSet
を例として取り上げ
java.sql.ResultSet
(
Enumeration
もロールします)。 Iterableではありません。つまり、JavaConversionsへの透過的な変換はないため、命令型で排他的に操作するか、中間の可変コレクションのコンテンツにコピーする必要があります。オプションとして、ビルダーを介して不変ビルドします。 怖い。
この場合、Scala標準ライブラリには、少なくとも
Traversable
である
ResultSet
から食用の
Iterator
を作成できるIteratorクラスがあります。
val resultSetIterator = Iterator.continually(resultSet).takeWhile(_.next())
単純な置換とバイナリロジック
呼び出しチェーンをより単純な、または1つの単純なメソッドで置き換えることができる場合、単純な置換ルールから始めましょう。 あなたを助けることができる最も簡単な方法は、
forall
と
find
です。 私はよく観察しました:
option.map(myValueIsGoodEnough).getOrElse(false)
代わりに
option.exists(goodEnoughValue) // `option exists goodEnoughValue`
それから
iterable.filter(goodEnough).headOption
代わりに
iterable.find(goodEnough)
それも起こりました(ただし、コード内で!)
iterable.foldLeft(true)(_ && goodEnough)
の代わりに
iterable.forall(goodEnough)
言うまでもなく、シンプルなオプションは読みやすいだけでなく、より効率的に実装されます。これは、
map
、
filter
、
foldLeft
がコレクションの長さに関係なくコレクション全体をチェックするためです。適切な(または不適切な)要素が見つかるとすぐに終了し、追加の中間コレクションは生成されません。
Coursera.comのScalaコースには 、
span
、
dropWhile
便利な機能もいくつか
dropWhile
ています。 それらを使用することは実際には明らかではないかもしれません。なぜなら、
filter
はこれらのケースでもうまく機能しますが、あまり効率的ではありません。なぜなら、彼はいつでも要素をチェックする必要がないことを知らないからです:それらはすべてすでに適合しているか適合していないからです。 たとえば、最近まで、私は自分自身が、
filter
、および
dropWhile
と
takeWhile
内ではなく、間隔内にない一連の為替レートの開始と終了をクリーン
dropWhile
し
takeWhile
。
集計
fold
、
foldLeft
および
foldRight
非常に強力であり、完全に異なる問題を解決するために使用できます。
たとえば、
foldLeft
について説明します。その助けを借りて、コレクションの要素の合計を取得できます。
iterable.foldLeft(0) { (accum, elem) => accum + elem }
このようなコードの標準的なスペルは次のとおりです。
iterable.foldLeft(0) { _ + _ }
これに対するMartin Oderskyは、Scala Daysで興味深いオプションを示しました。
(0 /: iterable)(_ + _)
ドミノが左から右に落ちるかのように言う:)プラスはここでより詳細に説明されていますが、主題領域でよく知られていない場合、私はまだ記号演算子に懐疑的です。
いずれにせよ、このような状況では、このコードを記述しないでください。タイプクラス
Numeric
要素を持つコレクションには特別なメソッドがあるため、より簡単に記述できます。
iterable.sum
min
max
と
max
機能も利用できます(専門職人はコレクションを並べ替えて頭/尾をとるのが好きです。私はこれをよく見ていません)。
高レベルアルゴリズムの手順を次々に適用するための折りたたみ方法を保存することをお勧めします。たとえば、責任の連鎖、またはmap-reduceでreduceを実行します。
時折グラフや一般的な情報を処理するときに、要素をペア(現在と前)で処理しなければならない場合があります。この場合、本当にしたいかもしれません。
for(i <- 1 until seq.size) { result ++= combine(seq(i-1), seq(i)) }
Scalaでは、1つの要素だけシフトされたシーケンスを縫い付けてから、両方の要素を処理する関数を適用できます。
seq.zip(seq.drop(1)).map(combine) // list.zip(list.tail).map(combine) // ,
シートが空でないことを必ず確認してください!
同じコードを記述する方がより正確です
seq.sliding(2).map(calculateDelta)
そして今、良いニュースです。JavaOneで、これらの単純化の多くをIntelliJのメンバーに登録することが判明しました。ScalaDaysによって既にそれらを実装することができました。
現在、Scalaの検査に関与している特別な人がいるので、単純化に関して興味深い考えがあれば、 チケットを作成してください。
良いコードを書いて幸せになりましょう。