【问题标题】:Idiomatic scala solution to combining sequences用于组合序列的惯用 scala 解决方案
【发布时间】:2013-09-19 22:51:02
【问题描述】:

想象一个函数combineSequences: (seqs: Set[Seq[Int]])Set[Seq[Int]],它在第一个序列的最后一项与第二个序列的第一项匹配时组合序列。例如,如果您有以下序列:

(1, 2)
(2, 3)
(5, 6, 7, 8)
(8, 9, 10)
(3, 4, 10)

combineSequences 的结果是:

(5, 6, 7, 8, 8, 9, 10)
(1, 2, 2, 3, 3, 4, 10)

因为序列 1、2 和 5 组合在一起。如果多个序列可以组合以产生不同的结果,则决定是任意的。例如,如果我们有序列:

(1, 2)
(2, 3)
(2, 4)

有两个正确答案。要么:

(1, 2, 2, 3)
(2, 4)

或者:

(1, 2, 2, 4)
(2, 3)

我只能想到一个非常必要且相当不透明的实现。我想知道是否有人有更惯用的scala解决方案。我已经遇到过几次相关的问题了。

【问题讨论】:

  • 第一个结果应该是 (5,6,7,8,8,9,10) 和 (1,2,2,3,3,4,10) 对吧?
  • xs.map(y => xs.foldLeft[Seq[Int]](y)((acc, b) => if(acc.last == b.head) acc ++ b ; else acc)) 最好我能在深夜想出这个。它把原件留在了场景中,所以不是一个完整的解决方案,但可能会让你走上正确的轨道
  • 我也很难在功能上进行思考。我最近写了一篇应该对你有帮助的博文:Map, reduce, and fold for the programmatically imperative | prose :: and :: conz
  • 您应该改用SortedSet[Seq[Int]],因为Set 不能保证您所依赖的序列的顺序。
  • @Chirlo 这对于解决方案来说不是必需的,特别是因为他不在乎他得到哪些可能的正确答案。

标签: scala functional-programming sequence seq


【解决方案1】:

当然不是最优化的解决方案,但我为了可读性而努力。

def combineSequences[T]( seqs: Set[Seq[T]] ): Set[Seq[T]] = {
  if ( seqs.isEmpty ) seqs
  else {
    val (seq1, otherSeqs) = (seqs.head, seqs.tail)
    otherSeqs.find(_.headOption == seq1.lastOption) match {
      case Some( seq2 ) => combineSequences( otherSeqs - seq2 + (seq1 ++ seq2) )
      case None =>
        otherSeqs.find(_.lastOption == seq1.headOption) match {
          case Some( seq2 ) => combineSequences( otherSeqs - seq2 + (seq2 ++ seq1) )
          case None => combineSequences( otherSeqs ) + seq1
        }
    }
  }
}

REPL 测试:

scala> val seqs = Set(Seq(1, 2), Seq(2, 3), Seq(5, 6, 7, 8), Seq(8, 9, 10), Seq(3, 4, 10))
seqs: scala.collection.immutable.Set[Seq[Int]] = Set(List(1, 2), List(2, 3), List(8, 9, 10), List(5, 6, 7, 8), List(3, 4, 10))
scala> combineSequences( seqs )
res10: Set[Seq[Int]] = Set(List(1, 2, 2, 3, 3, 4, 10), List(5, 6, 7, 8, 8, 9, 10))
scala> val seqs = Set(Seq(1, 2), Seq(2, 3, 100), Seq(5, 6, 7, 8), Seq(8, 9, 10), Seq(100, 4, 10))
seqs: scala.collection.immutable.Set[Seq[Int]] = Set(List(100, 4, 10), List(1, 2), List(8, 9, 10), List(2, 3, 100), List(5, 6, 7, 8))
scala> combineSequences( seqs )
res11: Set[Seq[Int]] = Set(List(5, 6, 7, 8, 8, 9, 10), List(1, 2, 2, 3, 100, 100, 4, 10))

【讨论】:

  • 这是一个很好的解决方案。如果您无法对列表进行预排序,有什么关于可读解决方案的想法吗?在做一个类似的问题时,我把它弄得太简单了。
  • 这实际上并不适用于我可以描述的所有序列,尽管它适用于我的示例。如果你有Seq(Seq(1, 2), Seq(2, 3, 100), Seq(5, 6, 7, 8), Seq(8, 9, 10), Seq(100, 4, 10) 怎么办?您不会在第二个 seq 和最后一个 seq 之间获得连接,因为它们不会彼此相邻排序。
  • 你说得对,我想我应该更多地关注需求而不是测试集。我更新了我的答案,我现在认为它是正确的,并且仍然比较容易理解。
猜你喜欢
  • 1970-01-01
  • 2021-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-03
  • 1970-01-01
相关资源
最近更新 更多