次のタプルのリストがあるとします。
val tuples = listOfStrings.map(string => {
val split = string.split(":")
(split(0), split(1), split(2))
})
リスト内のsplit(0)、別のリスト内のsplit(1)などを取得したいと思います。これを実現する簡単な方法は、次のように書くことです。
list1 = tuples.map(x => x._1).toList
list2 = tuples.map(x => x._2).toList
list3 = tuples.map(x => x._3).toList
3つの別々のステートメントを書かずに上記を達成するためのよりエレガントな(機能的な)方法はありますか?
これにより、結果がリストのリストとして表示されます。
tuples.map{t => List(t._1, t._2, t._3)}.transpose
それらをローカル変数に格納したい場合は、次のようにしてください。
val List(l1,l2,l3) = tuples.map{t => List(t._1, t._2, t._3)}.transpose
[〜#〜] update [〜#〜]:Blaisorbladeが指摘しているように、標準ライブラリには実際にはこれのための組み込みメソッドがあります:unzip3
、これはunzip
と同じですが、ペアではなくトリプルの場合:
val (l1, l2, l3) = tuples.unzip3
言うまでもなく、上記の私の手巻きソリューションよりもこの方法を優先する必要があります(ただし、アリティが3を超えるタプルの場合、これは引き続き適用されます)。
解凍したい:
scala> val (numbers, homonyms) = List(("one", "won"), ("two", "too")).unzip
numbers: List[Java.lang.String] = List(one, two)
homonyms: List[Java.lang.String] = List(won, too)
任意のタプルサイズに使用できるものが必要な場合:
val tupleSize = 3
0.until(tupleSize).toList
.map(x => (_:Product).productElement(x).asInstanceOf[String])
.map(tuples.map(_))
明らかに、代わりに配列のリストがあれば、これはよりエレガントに表現できます。
ステートメントを1行で書くことができます。
お気に入り
(list1, list2, list3) = tuples.foldRight((List[String](), List[String](), List[String]()))( (a,b) => (a._1 :: b._1, a._2 :: b._2, a._3 :: b._3 ) )
エレガントについてはわかりませんが、couldタプルを格納する中間ステップなしで1行で実行できます。多分それは少し読みにくいです...
(for(split <- listOfStrings.map(_.split(":")))
yield List(split(0), split(1), split(2))).transpose
replの例:
scala> listOfStrings
res1: List[Java.lang.String] = List(a:b:c, d:e:f, g:h:i)
scala> (for(split <- listOfStrings.map(_.split(":")))
| yield List(split(0), split(1), split(2))).transpose
res2: List[List[Java.lang.String]] = List(List(a, d, g), List(b, e, h), List(c, f, i))