我有一个包含以下数据顺序的序列:
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
我有一个概念性的理解,这可能涉及映射和压缩。我可以用命令式的方式在短时间内实现它,但我希望它是一种功能性的风格。
感谢任何帮助/指示,谢谢!
答案 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
但这是非常不透明的,所以将事情分散开来给评论留出空间是一个好主意。