8

2番目のリストの要素がn番目ごとの要素の後に1番目のリストに挿入されるように、任意の長さの2つのリストを結合したいと思います。1番目のリストの長さがn未満の場合、挿入は行われません。

だから持っている

val a = List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
val b = List(101,102,103)
val n = 3 

結果のリストを次のようにします。

List(1,2,3,101,4,5,6,102,7,8,9,103,10,11,12,13,14,15)

foldLeftonを使用してこれを機能させaていますが、Scalazを使用して同じロジックをどのように実現できるのでしょうか。

みんなの答えをありがとう。それらはすべて私に役立ちました!

4

6 に答える 6

8

私のアポモルフィズムの友達に会いましょう

def apo[A, B](v: B)(f: B => Option[(A, Either[B, List[A]])]): List[A] = f(v) match {
   case None => Nil
   case Some((a, Left(b)))   => a :: apo(b)(f)
   case Some((a, Right(as))) => a :: as 
}

インターリーブメソッドは次のように実装できます

def interleave[A](period: Int, substitutes: List[A], elems: List[A]): List[A] =
  apo((period, substitutes, elems)){
    case (_, _, Nil)       => None
    case (_, Nil, v :: vs) => Some((v, Right(vs)))
    case (0, x :: xs, vs)  => Some((x, Left((period, xs, vs))))
    case (n, xs, v :: vs)  => Some((v, Left((n - 1, xs, vs))))  
  }

これは与える:

scala> interleave(3, b, a)
res1: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103 , 10, 11 , 12, 13, 14, 15)

良い点は、foldLeftとは異なり、aまたはbがNilのときに計算が終了することです。悪いニュースは、インターリーブが末尾再帰ではなくなったことです

于 2012-07-06T10:48:41.247 に答える
5

これはで非常に簡単になりzipAllます。さらに、2番目の配列(この場合は1)の要素の量を選択できます。

val middle = b.grouped(1).toList
val res = a.grouped(n).toList.zipAll(middle, Nil, Nil)
res.filterNot(_._1.isEmpty).flatMap(x => x._1 ++ x._2)

または、必要に応じて、ワンライナー:

a.grouped(n).toList.zipAll(b.map(List(_)), Nil, Nil).filterNot(_._1.isEmpty).flatMap(x => x._1 ++ x._2)

暗黙のクラスを作成することもできるので、a.interleave(b, 3)またはオプションのthridパラメーターを使用して呼び出すことができますa.interleave(b, 3, 1)

于 2014-06-14T16:00:15.847 に答える
4

これはどう:

 def process[A](xs: List[A], ys: List[A], n: Int): List[A] = 
   if(xs.size <= n || ys.size == 0) xs
   else xs.take(n):::ys.head::process(xs.drop(n),ys.tail,n)

scala> process(a,b,n) 
res8: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)

scala> val a = List(1,2,3,4,5,6,7,8,9,10,11) 
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)

scala> process(a,b,n) 
res9: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11)

scala> val a = List(1,2,3,4,5,6,7,8,9) 
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> process(a,b,n) 
res10: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9)

scala> val a = List(1,2,3,4,5,6,7,8) 
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)

scala> process(a,b,n) 
res11: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8)

「最初のリストの長さがn未満の場合、挿入結果はありません」というリクエストの場合、コードは次のように変更されます。

 def process[A](xs: List[A], ys: List[A], n: Int): List[A] = 
   if(xs.size < n || ys.size == 0) xs
   else xs.take(n):::ys.head::process(xs.drop(n),ys.tail,n)
于 2012-07-06T03:08:17.427 に答える
3

どうですか:

def interleave[A](xs: Seq[A], ys: Seq[A], n: Int): Seq[A] = {
  val iter = xs grouped n
  val coll = iter zip ys.iterator flatMap { case (xs, y) => if (xs.size == n) xs :+ y else xs }
  (coll ++ iter.flatten).toIndexedSeq
}

scala> interleave(a, b, n)
res34: Seq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)

scala> interleave(1 to 2, b, n)
res35: Seq[Int] = Vector(1, 2)

scala> interleave(1 to 6, b, n)
res36: Seq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102)

scala> interleave(1 to 7 b, n)
res37: Seq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102, 7)

scala> interleave(1 to 7, Nil, n)
res38: Seq[Int] = Vector(1, 2, 3, 4, 5, 6, 7)

scala> interleave(1 to 7, Nil, -3)
java.lang.IllegalArgumentException: requirement failed: size=-3 and step=-3, but both must be positive

短いですが、最も効率的なソリューションではありません。たとえば、リストを使用して呼び出す場合、追加操作(:+および++)はコストがかかります(O(n))。

編集:ごめんなさい。私は今、あなたがScalazで解決策を持ちたいと思っていることに気づきました。それにもかかわらず、答えは役に立つかもしれないので、私はそれを削除しません。

于 2012-07-05T20:50:03.730 に答える
3

Scalazと再帰なし。

scala> a.grouped(n).zip(b.iterator.map{ Some(_) } ++ Iterator.continually(None)).flatMap{ case (as, e) => if (as.size == n) as ++ e else as }.toList
res17: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)

一般的な方法:

def filled[T, A, That](a: A, b: Seq[T], n: Int)(implicit bf: CanBuildFrom[A, T, That], a2seq: A => Seq[T]): That = {
  val builder = bf()
  builder.sizeHint(a, a.length / n)
  builder ++= a.grouped(n).zip(b.iterator.map{ Some(_) } ++ Iterator.continually(None)).flatMap{ case (as, e) => if(as.size == n ) as ++ e else as }
  builder.result()
}

使用法:

scala> filled("abcdefghijklmnopqrstuvwxyz", "1234", 3)
res0: String = abc1def2ghi3jkl4mnopqrstuvwxyz

scala> filled(1 to 15, 101 to 103, 3)
res1: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)

scala> filled(1 to 3, 101 to 103, 3)
res70: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 101)

scala> filled(1 to 2, 101 to 103, 3)
res71: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2)
于 2012-07-06T05:52:24.960 に答える
0

これがあなたが望むものです:

import scala.annotation.tailrec

@tailrec
final def interleave[A](base: Vector[A], a: List[A], b: List[A]): Vector[A] = a match {
  case elt :: aTail => interleave(base :+ elt, b, aTail)
  case _ => base ++ b
}

...

interleave(Vector.empty, a, b)
于 2017-03-23T18:19:07.830 に答える