使用Scala在一行中所有可能的单词正向组合

时间:2018-09-17 10:57:48

标签: scala

假设我的textFile = "a b c a b"中有一行,并且我希望输出为= (a,b) (a,c) (a,a) (a,b) (b,c) (b,a) (b,b) (c,a) (c,b) (a,b)。 到目前为止,我所做的是使用Scala的组合定义,但并没有出现重复的情况。

val combinations = textFile.flatMap { line =>
     line.split("[\\s*$&#/\"'\\,.:;?!\\[\\](){}<>~\\-_]+")
        .combinations(2).toList 
        .toSeq
        .map{ case arr => arr(0) -> arr(1) }

}

这样做,我得到的输出为:

(a,a)
(a,b)
(a,c)
(b,b)
(b,c)

还有其他获取我想要的输出的方法,因为我认为组合在这里不起作用?

4 个答案:

答案 0 :(得分:3)

拆分输入,将其转换为列表,使用tailsfor理解:

val input = "a b c a b".split(" ").toList
val result = for (h :: t <- input.tails; x <- t) yield (h, x)

结果如下:

result foreach println

打印

(a,b)
(a,c)
(a,a)
(a,b)
(b,c)
(b,a)
(b,b)
(c,a)
(c,b)
(a,b)

...或者只使用嵌套的while循环和两个显式索引ij到数组中...

答案 1 :(得分:2)

我认为没有内置功能可以做到这一点,所以我相信您必须手动进行操作:

val items = line.split("[\\s*$&#/\"'\\,.:;?!\\[\\](){}<>~\\-_]+").toList
val pairs = for {
  first :: rest <- items.tails.filter(_.nonEmpty)
  second <- rest
} yield (first, second)
pairs.toList

tails方法返回序列尾部的迭代器。对于您的示例,items.tails.filter(_.nonEmpty)返回具有以下列表的迭代器:

List(a, b, c, a, b)
List(b, c, a, b)
List(c, a, b)
List(a, b)
List(b)

然后,将每个列表分为first元素和具有rest模式匹配的first :: rest,并将first元素与每个元素配对rest

答案 2 :(得分:2)

已定义combinations方法来删除重复项,因此您不能将其用于解决方案。

有一个简单的递归解决方案:

def combos(letters: List[String]): List[(String, String)] =
  letters match {
    case Nil =>
      Nil
    case c :: tail =>
      tail.map(d => (c, d)) ::: combos(tail)
  }

这不是尾递归,因此它可能会变慢并占用大量内存,因此,如果您更关心性能而不是清晰度,那么这里是尾递归版本:

def combos(letters: List[String]) = {
  @tailrec
  def loop(letters: List[String], res: List[(String, String)]): List[(String, String)] =
    letters match {
      case Nil =>
        res
      case c :: tail =>
        loop(tail, res ::: tail.map(d => (c, d)))
    }

  loop(letters, List.empty[(String, String)])
}

答案 3 :(得分:1)

以防万一,如果您正在寻找不同的方式:

val myList = "a b c a b".split(" ").zipWithIndex
for (x <- myList; y <- myList if x._2 < y._2 ) yield (x._1, y._1)