Scalaでリストを浅くコピーしたい。
私は次のような何かをしたかった:
val myList = List("foo", "bar")
val myListCopy = myList.clone
ただし、cloneメソッドは保護されています。
Scalaでリストを浅くコピーしたい。
私は次のような何かをしたかった:
val myList = List("foo", "bar")
val myListCopy = myList.clone
ただし、cloneメソッドは保護されています。
ここに答えはありません:そうしないでください。AList
は不変であるため、コピーしてもまったく意味がありません。
いくつかの操作を考えてみましょう。
val list = List(1,2,3)
val l1 = 0 :: list
val l2 = "a" :: list
どちらl1
もl2
変更list
していませんが、どちらもを参照する新しいリストを作成しますlist
。
これを詳しく説明しましょう。コンストラクターList(1,2,3)
は3つの要素を作成し、シングルトンオブジェクトも使用しています。具体的には、次の要素をインスタンス化しています。
::(3, Nil)
::(2, reference to the previous element)
::(1, reference to the previous element)
そしてNil
、シングルトンオブジェクトです。識別子list
が実際に指しているのは、その最後の要素です。
ここで、に割り当てる0 :: list
とl1
、1つの新しいオブジェクトがインスタンス化されます。
::(0, reference to ::(1, etc))
もちろん、への参照があるので、4つの要素(または、数える場合は5つ)のリストlist
と考えることができます。l1
Nil
今l2
は同じタイプではありませんがlist
、それも参照しています!ここ:
::("a", reference to ::(1, etc))
ただし、これらすべてのオブジェクトに関する重要な点は、変更できないことです。セッターも、プロパティを変更するメソッドもありません。それらは、「ヘッド」(これを最初の要素と呼びます)に同じ値/参照を持ち、「テール」(これを2番目の要素と呼びます)に同じ参照を持ちます。
ただし、リストを変更しているように見えるメソッドがあります。ただし、新しいリストを作成しているので安心してください。例えば:
val l3 = list map (n => n + 1)
メソッドマップは、同じサイズの完全に新しいリストを作成します。このリストでは、の対応する要素から新しい要素を計算できlist
ます(ただし、古い要素も無視できます)。
val l4 = l2 filter (n => n.isInstanceOf[Int])
l4
と同じ要素がありますが(list
ただしタイプは異なります)、まったく新しいリストでもあります。このメソッドfilter
は、渡したルールに基づいて新しいリストを作成し、どの要素が入り、何が入らないかを示します。既存のリストを返す可能性がある場合に備えて、最適化を試みません。
val l5 = list.tail
これは新しいリストを作成しません。l5
代わりに、の既存の要素に割り当てるだけですlist
。
val l6 = list drop 2
繰り返しますが、新しいリストは作成されません。
val l7 = list take 1
ただし、これは新しいリストを作成します。これは、の最初の要素を変更しlist
て、テールがを指すようにすることができないためNil
です。
実装の詳細は次のとおりです。
List
抽象クラスです。::
これには、クラス(はい、それはクラスの名前です)とシングルトンオブジェクトの2つの子孫がありますNil
。List
は封印されているため、新しいサブクラスを追加することはできません。また::
、finalであるため、サブクラス化することはできません。
リストを変更するために何もすることはできませんが、一部の操作では内部的に可変状態を使用します。これはパフォーマンスに役立ちますが、ローカライズされているため、作成したプログラムがそれを検出したり、結果を被ったりすることはありません。他の関数がリストをどのように処理するか、またはリストを同時に使用しているスレッドの数に関係なく、必要に応じてリストを渡すことができます。
リストをフィルタリングするには:
val list = List(1,2,3,4,5)
//only evens
val evens = list.filter(e=>e%2 == 0)
println(list)
//--> List(1, 2, 3, 4, 5)
println(evens)
//--> List(2, 4)
ワイルドカードを使用して、いくつかの文字を保存することもできます。
val evens = list.filter(_%2==0)
上でコメントしたように、リストは不変であることに注意してください。つまり、これらの操作は元のリストを変更せず、実際に新しいリストを作成します。
:_ *タイプアノテーションを使用
scala> val l1 = List(1,2,3)
l1: List[Int] = List(1, 2, 3)
scala> val l2 = List(l1:_*)
l2: List[Int] = List(1, 2, 3)
アノテーションに関する詳細:Scala:Seqまたはvarargsのいずれかをとるコンストラクター