Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在scala中交错两个列表的元素_Scala_Scalaz - Fatal编程技术网

如何在scala中交错两个列表的元素

如何在scala中交错两个列表的元素,scala,scalaz,Scala,Scalaz,我希望将任意长度的两个列表组合在一起,这样第二个列表中的元素将插入第一个列表中的每个第n个元素之后。如果第一个列表长度小于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) 我在a上使用了foldLeft,但

我希望将任意长度的两个列表组合在一起,这样第二个列表中的元素将插入第一个列表中的每个第n个元素之后。如果第一个列表长度小于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)
我在
a
上使用了
foldLeft
,但我想知道如何使用Scalaz实现相同的逻辑

谢谢大家的回答。他们都对我很有帮助

那么:

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的解决方案。不过,答案可能有用,因此我不会删除它。

这个怎么样:

 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)

您的请求是“如果第一个列表长度小于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)
def进程[A](xs:List[A],ys:List[A],n:Int):List[A]=
如果(xs.size
没有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)

见见我的无形体朋友

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为零时,计算结束。坏消息是交织不再是尾部递归

这在
zipAll
中变得非常简单。此外,您还可以选择第二个数组的元素数量(在本例中为1):

或者,如果您愿意,一行:

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

您还可以创建一个隐式类,这样您可以调用
a.interleave(b,3)
,或者使用可选的第三个参数
a.interleave(b,3,1)
,我认为这是最简单的解决方案

val bi = b.toIterator
a.zipWithIndex.flatMap {case (el, i) =>
    if (bi.hasNext && (i-1)%n == n-1) List(bi.next, el) else List(el)
}

这是您想要的:

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)

如果a.size>3(b.size+1),那么您的解决方案的性能就不正确了@Antoras:是的,我正在使用
foldLeft
寻找一个比我的更优雅的解决方案。你的工作就是一个例子。然而,选择一个坏的例子是我的错,列表可能是任意长度的。所以
a.grouped(n).length
不一定等于
b.length
@marcin:稍微更改了我的代码。希望它现在能像预期的那样工作。
map+flatte
flatMap
@senia:我喜欢没有创意的填充,聪明。但是,如果
a.length
小于n,则会发生插入。我希望它只在
a.length>=n
@marcin时出现,很难通过组合来表达如此复杂的逻辑。在这种情况下,最好使用递归/循环。如果我理解正确的话,末日论和尾部递归是相互排斥的?对。您可能有具有“数千个大小”列表的SOE。请注意,在您的示例中,无同态比反同态(foldLeft)更有效,因为它将在b列表变为NilI后立即停止。我又发布了一个备选答案。似乎是最干净的-与折叠或直接递归相比,这有什么陷阱吗?我认为就性能而言,它可能介于折叠和递归之间
val bi = b.toIterator
a.zipWithIndex.flatMap {case (el, i) =>
    if (bi.hasNext && (i-1)%n == n-1) List(bi.next, el) else List(el)
}
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)