Scala Language
コレクション
サーチ…
リストをソートする
以下のリストを仮定すると、さまざまな方法を並べ替えることができます。
val names = List("Kathryn", "Allie", "Beth", "Serin", "Alana")
sorted()
のデフォルトの振る舞いは、 math.Ordering
を使用することmath.Ordering
。これは、文字列の場合、 レクソグラフィックソートになります。
names.sorted
// results in: List(Alana, Allie, Beth, Kathryn, Serin)
sortWith
使用すると、比較関数を使用して独自の順序をsortWith
できます。
names.sortWith(_.length < _.length)
// results in: List(Beth, Allie, Serin, Alana, Kathryn)
sortBy
使用すると、変換関数を指定できます。
//A set of vowels to use
val vowels = Set('a', 'e', 'i', 'o', 'u')
//A function that counts the vowels in a name
def countVowels(name: String) = name.count(l => vowels.contains(l.toLower))
//Sorts by the number of vowels
names.sortBy(countVowels)
//result is: List(Kathryn, Beth, Serin, Allie, Alana)
リストやソートされたリストを `reverse:
names.sorted.reverse
//results in: List(Serin, Kathryn, Beth, Allie, Alana)
リストはJavaメソッドjava.util.Arrays.sort
とそのScalaラッパーscala.util.Sorting.quickSort
を使用してソートすることもできます
java.util.Arrays.sort(data)
scala.util.Sorting.quickSort(data)
これらのメソッドは、コレクションの変換とアンボックス/ボクシングを避けることができれば、大きなコレクションをソートするときのパフォーマンスを向上させることができます。パフォーマンスの違いについての詳細な説明は、 Scala Collection sorted、sortWith、sortBy Performanceを参照してください 。
n個のコピーを含むリストを作成する
あるオブジェクトx
n
コピーのコレクションを作成するには、 fillメソッドを使用します。この例ではList
作成しますが、これはfill
が意味を持つ他のコレクションでも使えます:
// List.fill(n)(x)
scala > List.fill(3)("Hello World")
res0: List[String] = List(Hello World, Hello World, Hello World)
リストとベクトルのチートシート
実装のパフォーマンスが優れているため、
List
代わりにVector
を使用するのがベストプラクティスです 。 パフォーマンスの特性については、こちらをご覧ください 。Vector
どこに使用することができますList
使用されています。
リスト作成
List[Int]() // Declares an empty list of type Int
List.empty[Int] // Uses `empty` method to declare empty list of type Int
Nil // A list of type Nothing that explicitly has nothing in it
List(1, 2, 3) // Declare a list with some elements
1 :: 2 :: 3 :: Nil // Chaining element prepending to an empty list, in a LISP-style
要素を取る
List(1, 2, 3).headOption // Some(1)
List(1, 2, 3).head // 1
List(1, 2, 3).lastOption // Some(3)
List(1, 2, 3).last // 3, complexity is O(n)
List(1, 2, 3)(1) // 2, complexity is O(n)
List(1, 2, 3)(3) // java.lang.IndexOutOfBoundsException: 4
要素の前に追加
0 :: List(1, 2, 3) // List(0, 1, 2, 3)
要素を追加する
List(1, 2, 3) :+ 4 // List(1, 2, 3, 4), complexity is O(n)
結合(連結)リスト
List(1, 2) ::: List(3, 4) // List(1, 2, 3, 4)
List.concat(List(1,2), List(3, 4)) // List(1, 2, 3, 4)
List(1, 2) ++ List(3, 4) // List(1, 2, 3, 4)
一般的な操作
List(1, 2, 3).find(_ == 3) // Some(3)
List(1, 2, 3).map(_ * 2) // List(2, 4, 6)
List(1, 2, 3).filter(_ % 2 == 1) // List(1, 3)
List(1, 2, 3).fold(0)((acc, i) => acc + i * i) // 1 * 1 + 2 * 2 + 3 * 3 = 14
List(1, 2, 3).foldLeft("Foo")(_ + _.toString) // "Foo123"
List(1, 2, 3).foldRight("Foo")(_ + _.toString) // "123Foo"
マップコレクションのチートシート
これは
map
メソッドのコレクションとは異なるMap
型のコレクションの作成を扱うことに注意してください。
地図の作成
Map[String, Int]()
val m1: Map[String, Int] = Map()
val m2: String Map Int = Map()
マップは、ほとんどの操作のtuples
コレクションと見なすことができます。最初の要素はキーで、2番目の要素は値です。
val l = List(("a", 1), ("b", 2), ("c", 3))
val m = l.toMap // Map(a -> 1, b -> 2, c -> 3)
要素を取得する
val m = Map("a" -> 1, "b" -> 2, "c" -> 3)
m.get("a") // Some(1)
m.get("d") // None
m("a") // 1
m("d") // java.util.NoSuchElementException: key not found: d
m.keys // Set(a, b, c)
m.values // MapLike(1, 2, 3)
要素を追加する
Map("a" -> 1, "b" -> 2) + ("c" -> 3) // Map(a -> 1, b -> 2, c -> 3)
Map("a" -> 1, "b" -> 2) + ("a" -> 3) // Map(a -> 3, b -> 2)
Map("a" -> 1, "b" -> 2) ++ Map("b" -> 3, "c" -> 4) // Map(a -> 1, b -> 3, c -> 4)
一般的な操作
マップの反復が発生する操作( map
、 find
、 forEach
など)では、コレクションの要素はtuples
です。 functionパラメータは、タプルアクセサ( _1
、 _2
)、またはcaseブロックを含む部分関数を使用できます。
m.find(_._1 == "a") // Some((a,1))
m.map {
case (key, value) => (value, key)
} // Map(1 -> a, 2 -> b, 3 -> c)
m.filter(_._2 == 2) // Map(b -> 2)
m.foldLeft(0){
case (acc, (key, value: Int)) => acc + value
} // 6
コレクションの地図とフィルター
地図
コレクションの「マッピング」は、 map
関数を使用して、そのコレクションの各要素を同様の方法で変換します。一般的な構文は次のとおりです。
val someFunction: (A) => (B) = ???
collection.map(someFunction)
あなたは無名関数を提供することができます:
collection.map((x: T) => /*Do something with x*/)
整数に2を掛ける
// Initialize
val list = List(1,2,3)
// list: List[Int] = List(1, 2, 3)
// Apply map
list.map((item: Int) => item*2)
// res0: List[Int] = List(2, 4, 6)
// Or in a more concise way
list.map(_*2)
// res1: List[Int] = List(2, 4, 6)
フィルタ
filter
は、コレクションの特定の要素を除外または除外したいときに使用されます。 map
同様に、汎用構文は関数を取りますが、その関数はBoolean
返さなければなりません:
val someFunction: (a) => Boolean = ???
collection.filter(someFunction)
匿名関数を直接提供することができます:
collection.filter((x: T) => /*Do something that returns a Boolean*/)
ペア数の確認
val list = 1 to 10 toList
// list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// Filter out all elements that aren't evenly divisible by 2
list.filter((item: Int) => item % 2==0)
// res0: List[Int] = List(2, 4, 6, 8, 10)
その他のマップとフィルタの例
case class Person(firstName: String,
lastName: String,
title: String)
// Make a sequence of people
val people = Seq(
Person("Millie", "Fletcher", "Mrs"),
Person("Jim", "White", "Mr"),
Person("Jenny", "Ball", "Miss") )
// Make labels using map
val labels = people.map( person =>
s"${person.title}. ${person.lastName}"
)
// Filter the elements beginning with J
val beginningWithJ = people.filter(_.firstName.startsWith("J"))
// Extract first names and concatenate to a string
val firstNames = people.map(_.firstName).reduce( (a, b) => a + "," + b )
Scalaコレクションの紹介
Scala Collectionsフレームワークは、 その作者によれば 、使いやすく、簡潔で、安全で、速く、普遍的に設計されています。
フレームワークは、コレクションを作成するためのビルディングブロックとして設計されたScalaの特性で構成されています。これらのビルディングブロックの詳細については、公式Scalaコレクションの概要を読んでください 。
これらのビルトインコレクションは、変更可能なパッケージと変更可能なパッケージに分かれています。デフォルトでは、不変のバージョンが使用されます。 List()
(何もインポートすることなく)を作成すると、 不変のリストが作成されます。
このフレームワークの最も強力な機能の1つは、同じ考え方のコレクション間で一貫した使いやすいインターフェイスです。たとえば、コレクション内のすべての要素を合計することは、リスト、セット、ベクトル、配列および配列で同じです。
val numList = List[Int](1, 2, 3, 4, 5)
numList.reduce((n1, n2) => n1 + n2) // 15
val numSet = Set[Int](1, 2, 3, 4, 5)
numSet.reduce((n1, n2) => n1 + n2) // 15
val numArray = Array[Int](1, 2, 3, 4, 5)
numArray.reduce((n1, n2) => n1 + n2) // 15
これらの同種のタイプは、 Traversable
特性を継承しています。
実装のパフォーマンスが優れているため、
List
代わりにVector
を使用するのがベストプラクティスです 。 パフォーマンスの特性については、こちらをご覧ください 。Vector
どこに使用することができますList
使用されています。
トラバーサルタイプ
Traversable
traitを持つコレクションクラスはforeach
を実装し、コレクションに対して共通の操作を実行するための多くのメソッドを継承します。これらのメソッドはすべて同じように機能します。最も一般的な操作は次のとおりです。
- Map -
map
、flatMap
、およびcollect
は、元のコレクションの各要素に関数を適用して、新しいコレクションcollect
生成します。
List(1, 2, 3).map(num => num * 2) // double every number = List(2, 4, 6)
// split list of letters into individual strings and put them into the same list
List("a b c", "d e").flatMap(letters => letters.split(" ")) // = List("a", "b", "c", "d", "e")
- コンバージョン -
toList
、toArray
などのコンバージョン操作では、現在のコレクションをより特定の種類のコレクションに変更します。これらは、通常、 'to'で始まるメソッドとより具体的な型です(つまり、 'toList'はList
変換されます)。
val array: Array[Int] = List[Int](1, 2, 3).toArray // convert list of ints to array of ints
- サイズ情報 -
isEmpty
、nonEmpty
、size
、およびhasDefiniteSize
は、セットに関するすべてのメタデータです。これにより、コレクションの条件付き操作が可能になります。また、コードがコレクションのサイズ(無限か離散かなど)を決めることができます。
List().isEmpty // true
List(1).nonEmpty // true
val list = List(1, 2, 3)
list.head // = 1
list.last // = 3
- サブコレクション検索操作 -
filter
、tail
、slice
、drop
などの操作により、コレクションの一部を選択してさらに操作できます。
List(-2, -1, 0, 1, 2).filter(num => num > 0) // = List(1, 2)
-
partition
操作 -partition
、splitAt
、span
、およびgroupBy
は、現在のコレクションを異なる部分に分割します。
// split numbers into < 0 and >= 0
List(-2, -1, 0, 1, 2).partition(num => num < 0) // = (List(-2, -1), List(0, 1, 2))
- 要素テスト -
exists
、forall
およびcount
は、このコレクションをチェックして述語を満たしているかどうかを調べるために使用される操作です。
List(1, 2, 3, 4).forall(num => num > 0) // = true, all numbers are positive
List(-3, -2, -1, 1).forall(num => num < 0) // = false, not all numbers are negative
- Folds -
foldLeft
(/:
foldLeft
、foldRight
(:\
)、reduceLeft
、およびreduceRight
は、コレクション内の連続する要素にバイナリ関数を適用するために使用されます。 折り畳みの例について はこちらへ、縮小の例についてはここに移動してください 。
折りたたむ
fold
メソッドは、最初のアキュムレータ値を使用し、各要素を使用してアキュムレータを正常に更新する関数を適用して、コレクションに対して反復処理を行います。
val nums = List(1,2,3,4,5)
var initialValue:Int = 0;
var sum = nums.fold(initialValue){
(accumulator,currentElementBeingIterated) => accumulator + currentElementBeingIterated
}
println(sum) //prints 15 because 0+1+2+3+4+5 = 15
上記の例では、 fold()
無名関数が提供されています。また、2つの引数を取る名前付き関数を使うこともできます。これを私の中に入れて、上記の例を次のように書き直すことができます:
def sum(x: Int, y: Int) = x+ y
val nums = List(1, 2, 3, 4, 5)
var initialValue: Int = 0
val sum = nums.fold(initialValue)(sum)
println(sum) // prints 15 because 0 + 1 + 2 + 3 + 4 + 5 = 15
初期値を変更すると結果に影響します:
initialValue = 2;
sum = nums.fold(initialValue){
(accumulator,currentElementBeingIterated) => accumulator + currentElementBeingIterated
}
println(sum) //prints 17 because 2+1+2+3+4+5 = 17
fold
メソッドにはfoldLeft
とfoldRight
2つのバリエーションがありfoldRight
。
foldLeft()
は左から右へ(コレクションの最初の要素からその順序の最後までfoldLeft()
繰り返します。 foldRight()
、右から左へ(最後の要素から最初の要素までfoldRight()
繰り返します。 fold()
foldLeft()
ように左から右に反復します。実際、 fold()
はfoldLeft()
内部的に呼び出します。
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)
fold()
、 foldLeft()
およびfoldRight()
は、初期値と同じ型の値を返します。しかし、とは異なりfoldLeft()
とfoldRight()
するために与えられ、初期値fold()
だけ同じタイプまたはコレクションのタイプのスーパータイプのものとすることができます。
この例では、順序は関係ありません。したがって、 fold()
をfoldLeft()
またはfoldRight()
と結果は変わりません。順序に敏感な関数を使用すると、結果が変更されます。
疑問がある場合は、 foldLeft()
よりfoldLeft()
をfoldRight()
してfoldRight()
。 foldRight()
はパフォーマンスが低下します。
フォアハ
foreach
はコレクションイテレータの中では結果を返さない点で珍しいです。代わりに、副作用のみを持つ各要素に関数を適用します。例えば:
scala> val x = List(1,2,3)
x: List[Int] = List(1, 2, 3)
scala> x.foreach { println }
1
2
3
foreach
れる関数は任意の戻り値型を持つことができますが、結果は破棄されます。通常、 foreach
は、副作用が望ましい場合に使用されます。データを変換する場合は、 map
、 filter
、 for comprehension
のfor comprehension
、または別のオプションを使用することを検討してください。
結果の破棄の例
def myFunc(a: Int) : Int = a * 2
List(1,2,3).foreach(myFunc) // Returns nothing
減らす
reduce()
、 reduceLeft()
、およびreduceRight
メソッドは、折り畳みに似ています。 reduceに渡される関数は2つの値をとり、3つ目の値を返します。リストを操作する場合、最初の2つの値はリストの最初の2つの値です。関数の結果とリストの次の値は、関数に再適用され、新しい結果が返されます。この新しい結果は、リストの次の値に適用され、要素がなくなるまで続きます。最終結果が返されます。
val nums = List(1,2,3,4,5)
sum = nums.reduce({ (a, b) => a + b })
println(sum) //prints 15
val names = List("John","Koby", "Josh", "Matilda", "Zac", "Mary Poppins")
def findLongest(nameA:String, nameB:String):String = {
if (nameA.length > nameB.length) nameA else nameB
}
def findLastAlphabetically(nameA:String, nameB:String):String = {
if (nameA > nameB) nameA else nameB
}
val longestName:String = names.reduce(findLongest(_,_))
println(longestName) //prints Mary Poppins
//You can also omit the arguments if you want
val lastAlphabetically:String = names.reduce(findLastAlphabetically)
println(lastAlphabetically) //prints Zac
折り畳み機能と比較して、縮小機能がどのように機能するかにはいくつかの違いがあります。彼らです:
- reduce関数には初期アキュムレータ値はありません。
- 関数を空リストで呼び出すことはできません。
- Reduce関数は、リストの型またはスーパータイプのみを返すことができます。