将元素应用于List中的连续元素

时间:2015-09-12 04:49:54

标签: scala

我正在寻找一种方法来应用List中的每个元素及其在Scala中的连续元素,而无需编写嵌套的for循环。基本上我正在寻找一个允许我执行以下操作的List理解:

A = {a, b, c, d}

然后A' = {ab, ac, ad, bc, bd, cd}

我考虑过使用map例如A.map(x => ...),但我无法弄清楚语句的其余部分是什么样的。

希望这一切都有道理。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:6)

这对于递归评估来说似乎很自然。因为它将第一个元素添加到列表的其余部分,然后使用应用于列表其余部分的相同内容。

def pairs(xs: List[Char]): List[String] = xs match {
  case Nil | _ :: Nil => Nil
  case y :: ys        => ys.map(z => s"$y$z") ::: pairs(ys)
}

pairs(a) //> res0: List[String] = List(ab, ac, ad, bc, bd, cd)

尾递归

def pairs2(xs: List[Char], acc:List[String]): List[String] = xs match {
  case Nil | _ :: Nil => acc.reverse
  case y :: ys        => pairs2(ys, ys.foldLeft(acc){(acc, z) => s"$y$z"::acc})
}

pairs2(a, Nil)  //> res0: List[String] = List(ab, ac, ad, bc, bd, cd)

或者,如果你真的想要理解:

val res = for {(x::xs) <- a.tails
                y <- xs
              } 
            yield s"$x$y"

(返回一个迭代器,所以强制其评估)

res.toList //> res1: List[String] = List(ab, ac, ad, bc, bd, cd)

这表明另一种变体,来自贬低

a.tails.collect{case(x::xs) => xs.map(y=>s"$x$y")}.flatten.toList
//> res2: List[String] = List(ab, ac, ad, bc, bd, cd)

答案 1 :(得分:2)

记住在Scala中我们所拥有的是“for-comprehension”而不是Java意义上的“for-loop”,这种结构不像Java那样“嵌套”。具体来说,它看起来像:

// For a list of items of some type 'A':
val items: List[A] = ???

// and some suitable combining function (which might be inlined if simple enough):
def fn(i1: A, i2: A): A = ???

// an example for-comprehension that will achieve the output you describe:
for {
  x <- items.zipWithIndex
  y <- items.zipWithIndex
  z <- List(fn(x._1, y._1)) if (x._2 < y._2) 
} yield z

对我来说似乎足够干净。这可以解释为:

items.zipWithIndex.flatMap( x => 
  items.zipWithIndex.flatMap( y => 
    List(fn(x._1, y._1)).withFilter( z => x._2 < y._2 ).map( z => z ) ) )

虽然你特别要求的“列表理解”的内容更多,但对我来说似乎不那么清楚了!

答案 2 :(得分:1)

如果你正在组合Strings,你可以做这样的事情。

scala> List("a","b","c","d").combinations(2).map(s => s.head+s.last).toList
res5: List[String] = List(ab, ac, ad, bc, bd, cd)

但是你把它称为&#34;一种应用每个元素的方法&#34;所以也许你的意思是别的?如果是这样,也许这种方法可以让你开始。