9

私がこれを持っている場合:

val a = Array("a ","b ","c ")
val b = Array("x","y")

最初のコレクションをトラバースできるような方法が存在するかどうかを知りたいのですが、その要素ごとに、2番目のコレクション全体を歩きます。たとえば、配列をとると、、、、、、、、aになります。私はzipを知っていますが、私が見たところ、それは同じサイズのコレクションでのみ機能し、同じ位置の要素を関連付けます。a,xa,yb,xb,yc,xc,y

4

5 に答える 5

25

「メソッド」はわかりませんが、これはネストされた/複合語だけで表現できますfor

val a = Array("a ","b ","c ")
val b = Array("x","y")
for (a_ <- a; b_ <- b) yield (a_, b_)

res0: Array[(java.lang.String, java.lang.String)] = Array((a ,x), (a ,y), (b ,x), (b ,y), (c ,x), (c ,y))

ハッピーコーディング。

于 2011-05-10T20:11:13.783 に答える
6

私は自分のコードで以下を広範囲に使用しています。これは任意の数のリストに対して機能していることに注意してください。コレクションの代わりにイテレータを作成しているので、潜在的に巨大な結果をメモリに保存する必要はありません。

どんな改善も大歓迎です。

/**
  * An iterator, that traverses every combination of objects in a List of Lists.
  * The first Iterable will be incremented fastest. So consider the head as 
  * the "least significant" bit when counting.*/

class CombinationIterator[A](val components: List[Iterable[A]]) extends Iterator[List[A]]{
  private var state: List[BufferedIterator[A]] = components.map(_.iterator.buffered)
  private var depleted = state.exists(_.isEmpty)

  override def next(): List[A] = {
    //this function assumes, that every iterator is non-empty    
    def advance(s: List[(BufferedIterator[A],Iterable[A])]): List[(BufferedIterator[A],A)] = {
      if( s.isEmpty ){
        depleted = true
        Nil
      }
      else {
        assert(!s.head._1.isEmpty)

        //advance and return identity
        val it = s.head._1
        val next = it.next()
        if( it.hasNext){
          //we have simply incremented the head, so copy the rest
          (it,next) :: s.tail.map(t => (t._1,t._1.head))
        } else {
          //we have depleted the head iterator, reset it and increment the rest
          (s.head._2.iterator.buffered,next) :: advance(s.tail)
        }
      }
    }
    //zipping the iterables to the iterators is needed for resseting them
    val (newState, result) = advance(state.zip(components)).unzip
    
    //update state
    state = newState    
    
    result
  }

  override def hasNext = !depleted
}

したがって、これを使用して、new CombinationIterator(List(a,b))すべての組み合わせを実行するイテレータを取得するように記述する必要があります。

編集:ユーザー不明のバージョンに基づく

次のバージョンは最適ではないことに注意してください(パフォーマンスの観点から)。

  • リストへのインデックス付きアクセス(代わりに配列を使用)
  • takeWhileはすべての要素の後に評価します

scala> def combination(xx: List[List[_]], i: Int): List[_] = xx match {
     | case Nil => Nil
     | case x :: xs => x(i % x.length) :: combination(xs, i/x.length)
     | }
combination: (xx: List[List[_]], i: Int)List[_]

scala> def combinationIterator(ll: List[List[_]]): Iterator[List[_]] = {
     | Iterator.from(0).takeWhile(n => n < ll.map(_.length).product).map(combination(ll,_))
     | }
combinationIterator: (ll: List[List[_]])Iterator[List[_]]

scala> List(List(1,2,3),List("a","b"),List(0.1,0.2,0.3))
res0: List[List[Any]] = List(List(1, 2, 3), List(a, b), List(0.1, 0.2, 0.3))
    
scala> combinationIterator(res0)
res1: Iterator[List[_]] = non-empty iterator

scala> res1.mkString("\n")
res2: String = 
List(1, a, 0.1)
List(2, a, 0.1)
List(3, a, 0.1)
List(1, b, 0.1)
List(2, b, 0.1)
List(3, b, 0.1)
List(1, a, 0.2)
List(2, a, 0.2)
List(3, a, 0.2)
List(1, b, 0.2)
List(2, b, 0.2)
List(3, b, 0.2)
List(1, a, 0.3)
List(2, a, 0.3)
List(3, a, 0.3)
List(1, b, 0.3)
List(2, b, 0.3)
List(3, b, 0.3)
于 2011-05-10T21:09:07.883 に答える
6

不明な数のリスト、長さの異なるリスト、およびタイプの異なるリストの場合は、次を使用できます。

def xproduct (xx: List [List[_]]) : List [List[_]] = 
  xx match {
    case aa :: bb :: Nil => 
      aa.map (a => bb.map (b => List (a, b))).flatten       
    case aa :: bb :: cc => 
      xproduct (bb :: cc).map (li => aa.map (a => a :: li)).flatten
    case _ => xx
}

あなたはそれを呼ぶでしょう

xproduct List (List ("a ", "b ", "c "), List ("x", "y"))

しかし、別の種類のリストでも呼び出すことができます。

scala>  xproduct (List (List ("Beatles", "Stones"), List (8, 9, 10), List ('$', '€')))  
res146: List[List[_]] = List(List(Beatles, 8, $), List(Stones, 8, $), List(Beatles, 8, €), List(Stones, 8, €), List(Beatles, 9, $), List(Stones, 9, $), List(Beatles, 9, €), List(Stones, 9, €), List(Beatles, 10, $), List(Stones, 10, $), List(Beatles, 10, €), List(Stones, 10, €))

リストを使用できない場合は、配列をリストに変換し、結果を配列に変換し直す必要があります。

アップデート:

怠惰なコレクションに向かう途中で、インデックス(0からcombination-size -1まで)からその位置での結果への関数マッピングを作成しました。モジュロと除算で簡単に計算できます。必要なのはほんの少しの集中です。

def combicount (xx: List [List[_]]): Int = (1 /: xx) (_ * _.length)

def combination (xx: List [List[_]], i: Int): List[_] = xx match {
    case Nil => Nil
    case x :: xs => x(i % x.length) :: combination (xs, i / x.length)
}

def xproduct (xx: List [List[_]]): List [List[_]] = 
  (0 until combicount (xx)).toList.map (i => combination (xx, i))

代わりにlongを使用しても、BigIntを使用しても問題ありません。

アップデート2、イテレータ:

class Cartesian (val ll: List[List[_]]) extends Iterator [List[_]] {

  def combicount (): Int = (1 /: ll) (_ * _.length)

  val last = combicount - 1 
  var iter = 0
  
  override def hasNext (): Boolean = iter < last
  override def next (): List[_] = {
    val res = combination (ll, iter)
    iter += 1
    res
  }

  def combination (xx: List [List[_]], i: Int): List[_] = xx match {
      case Nil => Nil
      case x :: xs => x (i % x.length) :: combination (xs, i / x.length) 
  }
}
于 2011-05-11T03:45:41.890 に答える
4

より高い種類の型と圏論についての深い知識を誇示したい場合は、次のように書くことができます。

trait Applicative[App[_]] {
  def pure[A](a: A): App[A]
  def fmap[A,B](f: A => B, appA: App[A]): App[B]
  def star[A,B](appF: App[A => B], appA: App[A]): App[B]
}

object ListApplicative extends Applicative[List] {
  override def pure[A](a: A): List[A] = List(a)
  override def fmap[A,B](f: A => B, listA: List[A]): List[B] = listA.map(f)
  override def star[A,B](listF: List[A => B], listA: List[A]):List[B] = 
    for(f <- listF; a <- listA) yield f(a)
}

import ListApplicative._

def pairs[A,B](listA: List[A], listB: List[B]) = 
  star(fmap((a:A) => ((b:B) => (a,b)), listA), listB)

それ以外は、pstのソリューションをお勧めします...

于 2011-05-11T06:53:22.240 に答える
1

これは、@ ziggystarの最後の編集と同じことを行うが、リストのインデックス付きアクセスを使用しないもう1つです。

def combinationIterator[A](xs: Iterable[Iterable[A]]): Iterator[List[A]] = {
  xs.foldRight(Iterator(List[A]())) { (heads, tails) =>
    tails.flatMap { tail =>
      heads.map(head => head :: tail)
    }
  }
}

そして甘いバージョン:

def combinationIterator[A](xs: Iterable[Iterable[A]]): Iterator[List[A]] = {
  (xs :\ Iterator(List[A]())) { (heads, tails) =>
    for (tail <- tails; head <- heads) yield head :: tail
  }
}
于 2015-02-13T17:48:13.060 に答える