在Scala中重新排序序列

时间:2014-07-04 15:20:03

标签: scala

我有一个包含以下数据顺序的序列:

A, B, C, D, E, F, G, H, I, J, K, L, M, N, O

我需要对它进行排序,使它看起来像这样:

A, F, K, B, G, L, C, H, M, D, I, N, E, J, O

基本上将第一个序列分组为三个组,将它们堆叠在彼此的顶部,然后读取第一列,然后读取下一个序列以形成新序列。

ABCDE

FGHIJ

KLMNO

我有一个概念性的理解,这可能涉及映射和压缩。我可以用命令式的方式在短时间内实现它,但我希望它是一种功能性的风格。

感谢任何帮助/指示,谢谢!

2 个答案:

答案 0 :(得分:8)

你走了:

val xs = Seq('A, 'B, 'C, 'D, 'E, 'F, 'G, 'H, 'I, 'J, 'K, 'L, 'M, 'N, 'O)
val grouped = xs.grouped(5).toList
// List(List('A, 'B, 'C, 'D, 'E), List('F, 'G, 'H, 'I, 'J), List('K, 'L, 'M, 'N, 'O))
val result = grouped.transpose.flatten
// List('A, 'F, 'K, 'B, 'G, 'L, 'C, 'H, 'M, 'D, 'I, 'N, 'E, 'J, 'O)

答案 1 :(得分:2)

任何解决方案都应该从grouped开始,将集合切成碎片:

scala> val g = "ABCDEFGHIJKLMN".grouped(5)
g: Iterator[String] = non-empty iterator   // Will return "ABCDE", then "FGHIJ", then "KLMN"

然后我们将所有内容都变成一个列表,这样我们就可以轻松地采取行动:

scala> val l = g.map(_.toList).toList
List[List[Char]] = List(List(A, B, C, D, E), List(F, G, H, I, J),
                        List(K, L, M, N))

现在我们通过连续尾巴收集它们,在没有任何东西时停止:

scala> val i = Iterator.iterate(l)(_.map(_ drop 1).filter(_.nonEmpty)).takeWhile(_.nonEmpty)
i: Iterator[List[List[Char]]] = non-empty iterator
// List(List(A, B, C, D, E), List(F, G, H, I, J), List(K, L, M, N))
// List(List(B, C, D, E), List(G, H, I, J), List(L, M, N))
// List(List(C, D, E), List(H, I, J), List(M, N))
// List(List(D, E), List(I, J), List(N))
// List(List(E), List(J))

这看起来很大,但由于我们使用的是List,因此较短的列表与较长的列表共享内存,所以它的大小不是O(n ^ 2)爆炸。但我们真的只是想要头脑,我们已经把所有东西都过滤掉了,所以我们可以做到:

scala> val h = i.map(_.map(_.head))
h: Iterator[List[Char]] = non-empty iterator
// List(A, F, K)
// List(B, G, L)
// List(C, H, M)
// List(D, I, N)
// List(E, J)

最后从迭代器转换为严格集合并展平:

scala> val ans = h.toList.flatten
ans: List[Char] = List(A, F, K, B, G, L, C, H, M, D, I, N, E, J)

(如果您想要mkString返回,请添加String

请注意,临时变量仅用于解释清楚。如果你想把它全部写在一条线上,你可以。 (这是一个相当长的路线。)

(另请注意,如果您打印出迭代器,它们会被消耗掉。)

这是一举一动:

("ABCDEFGHIJKLMN".grouped(5).map(_.toList).toList match {
  case l => Iterator.iterate(l)(_.map(_ drop 1).filter(_.nonEmpty)).takeWhile(_.nonEmpty)
 }).map(_.map(_.head)).toList.flatten

但这是非常不透明的,所以将事情分散开来给评论留出空间是一个好主意。