我想组合两个任意长度的列表,使得第二个列表中的元素在每个第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)
我在foldLeft
上使用a
工作,但我想知道如何使用Scalaz完成相同的逻辑?
感谢大家的回答。他们对我都有帮助!
答案 0 :(得分:6)
认识我的apomorphism朋友
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)
好处是,当a或b为Nil时计算结束,与foldLeft不同。坏消息是交错不再是尾递归
答案 1 :(得分: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)
答案 2 :(得分:4)
使用zipAll
变得非常简单。此外,您可以选择第二个数组的元素数量(在本例中为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)
。
答案 3 :(得分: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)
)。
答案 4 :(得分: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)
答案 5 :(得分:0)
我认为这是最简单的解决方案。
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)
}
答案 6 :(得分:0)
这是你想要的那个:
&#xA;&#xA; import scala.annotation.tailrec&#xA;&#xA; @ tailrec&#xA; final def interleave [A ](base:Vector [A],a:List [A],b:List [A]):Vector [A] =匹配{&#xA; case elt :: aTail =&gt; interleave(base:+ elt,b,aTail)&#xA; case _ =&gt; base ++ b&#xA;}&#xA;&#xA; ...&#xA;&#xA; interleave(Vector.empty,a,b)&#xA;
& #xA;