56

Scalaでトラバース可能なものを操作する二項演算子cross(外積/デカルト積)が必要です。

val x = Seq(1, 2)
val y = List('hello', 'world', 'bye')
val z = x cross y    # i can chain as many traversables e.g. x cross y cross w etc

assert z == ((1, 'hello'), (1, 'world'), (1, 'bye'), (2, 'hello'), (2, 'world'), (2, 'bye'))

Scalaでのみこれを行うための最良の方法は何ですか(つまり、scalazのようなものを使用しない)?

4

8 に答える 8

88

これは、Scala2.10の暗黙のクラスとfor-comprehensionを使用して非常に簡単に行うことができます。

implicit class Crossable[X](xs: Traversable[X]) {
  def cross[Y](ys: Traversable[Y]) = for { x <- xs; y <- ys } yield (x, y)
}

val xs = Seq(1, 2)
val ys = List("hello", "world", "bye")

そして今:

scala> xs cross ys
res0: Traversable[(Int, String)] = List((1,hello), (1,world), ...

これは2.10より前で可能です。クラスと暗黙の変換メソッドの両方を定義する必要があるため、それほど簡潔ではありません。

これを書くこともできます:

scala> xs cross ys cross List('a, 'b)
res2: Traversable[((Int, String), Symbol)] = List(((1,hello),'a), ...

xs cross ys cross zsただし、を返却する場合Tuple3は、大量の定型文またはShapelessのようなライブラリが必要になります。

于 2013-02-06T22:45:34.533 に答える
31

クロスx_listアンドy_listウィズ:

val cross = x_list.flatMap(x => y_list.map(y => (x, y)))
于 2018-01-09T06:22:27.903 に答える
14

これは、任意の数のリストの再帰外積の実装です。

def crossJoin[T](list: Traversable[Traversable[T]]): Traversable[Traversable[T]] =
  list match {
    case xs :: Nil => xs map (Traversable(_))
    case x :: xs => for {
      i <- x
      j <- crossJoin(xs)
    } yield Traversable(i) ++ j
  }

crossJoin(
  List(
    List(3, "b"),
    List(1, 8),
    List(0, "f", 4.3)
  )
)

res0: Traversable[Traversable[Any]] = List(List(3, 1, 0), List(3, 1, f), List(3, 1, 4.3), List(3, 8, 0), List(3, 8, f), List(3, 8, 4.3), List(b, 1, 0), List(b, 1, f), List(b, 1, 4.3), List(b, 8, 0), List(b, 8, f), List(b, 8, 4.3))
于 2017-02-07T17:12:46.913 に答える
8

猫のユーザーのための代替手段:

sequenceList[List[A]]クロス積を作成します:

import cats.implicits._

val xs = List(1, 2)
val ys = List("hello", "world", "bye")

List(xs, ys).sequence 
//List(List(1, hello), List(1, world), List(1, bye), List(2, hello), List(2, world), List(2, bye))
于 2020-10-02T15:15:17.110 に答える
2
class CartesianProduct(product: Traversable[Traversable[_ <: Any]]) {
  override def toString(): String = {
    product.toString
  }

  def *(rhs: Traversable[_ <: Any]): CartesianProduct = {
      val p = product.flatMap { lhs =>
        rhs.map { r =>
          lhs.toList :+ r
        }
      }

      new CartesianProduct(p)
  }
}

object CartesianProduct {
  def apply(traversable: Traversable[_ <: Any]): CartesianProduct = {
    new CartesianProduct(
      traversable.map { t =>
        Traversable(t)
      }
    )
  }
}

// TODO: How can this conversion be made implicit?
val x = CartesianProduct(Set(0, 1))
val y = List("Alice", "Bob")
val z = Array(Math.E, Math.PI)

println(x * y * z) // Set(List(0, Alice, 3.141592653589793), List(0, Alice, 2.718281828459045), List(0, Bob, 3.141592653589793), List(1, Alice, 2.718281828459045), List(0, Bob, 2.718281828459045), List(1, Bob, 3.141592653589793), List(1, Alice, 3.141592653589793), List(1, Bob, 2.718281828459045))

// TODO: How can this conversion be made implicit?
val s0 = CartesianProduct(Seq(0, 0))
val s1 = Seq(0, 0)

println(s0 * s1) // List(List(0, 0), List(0, 0), List(0, 0), List(0, 0))
于 2016-12-06T00:34:02.777 に答える
2

これはMiladの応答に似ていますが、再帰的ではありません。

def cartesianProduct[T](seqs: Seq[Seq[T]]): Seq[Seq[T]] = {
  seqs.foldLeft(Seq(Seq.empty[T]))((b, a) => b.flatMap(i => a.map(j => i ++ Seq(j))))
}

このブログ投稿に基づいています。

于 2018-04-30T17:31:02.573 に答える
0

他の回答と同様に、私のアプローチだけです。

def loop(lst: List[List[Int]],acc:List[Int]): List[List[Int]] = {
  lst match {
    case head :: Nil => head.map(_ :: acc)
    case head :: tail => head.flatMap(x => loop(tail,x :: acc))
    case Nil => ???
  }
}
val l1 = List(10,20,30,40)
val l2 = List(2,4,6)
val l3 = List(3,5,7,9,11)

val lst = List(l1,l2,l3)

loop(lst,List.empty[Int])
于 2019-04-04T11:34:08.967 に答える
0

あなたはアプリケーションを使用することができます:

import cats.implicits._
(xs,ys).mapN((x,y) => (x,y))
于 2022-02-21T14:41:47.647 に答える