我在想怎么把数组分割成重叠的块。
作为示例,这是输入:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
这是预期的输出(块大小为3):[[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]
我开始使用stride(通过Hacking With Swift):
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
这当然给出了这个不正确的输出:[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
我找不到stride
的任何变体来获得预期的结果,所以就这样做了,使用两个嵌套的for-loops
:
extension Array {
func chunked2(into size: Int) -> [[Element]] {
var result: [[Element]] = []
for i in 0...self.count {
var chunk: [Element] = []
for j in i..<i+size {
if j < self.count {
chunk.append(self[j])
}
}
if chunk.count == size {
result.append(chunk)
}
}
return result
}
}
这是可行的,并给出了预期的结果。
问:我想知道我是否可以用一种更“敏捷”的方式重写它,使用像stride
,map
,也许reduce
或其他我缺少的函数?
3条答案
按热度按时间6uxekuva1#
你所描述的就是所谓的“窗口”。“它在数字信号处理中非常常见,并且在swift-algorithms中开箱即用。有关swift-algorithms包及其在Swift生态系统中的作用的更多信息,请参阅Announcing Swift Algorithms。
如果你想看一个算法如何工作的例子,请查看the source。他们使用数据结构WindowsOfCountCollection来实现它,而不是创建一堆zip等。这通常更有效,因为窗口是按需生成的,并且不必预先分配大量内存。
72qzrwbm2#
我想知道我是否可以用一种更“迅捷”的方式重写它,使用像stride,map,reduce或其他我缺少的功能?“**.
是的,您可以使用集合
func sequence<T, State>(state: State, next: @escaping (inout State) -> T?) -> UnfoldSequence<T, State>
方法创建自己的方法,如下所示:使用方法:
这将打印:
[一、二、三]
[二、三、四]
[3、4、5]
[4、5、6]
[5、6、7]
[6、7、8]
[7、8、9]
[8、9、10]
请注意,结果序列的元素是惰性计算的。它将返回一个UnfoldSequence,而不复制原始元素。
如果你需要输出一个子序列数组,你可以这样做:
如果你真的需要复制结果元素并输出数组的数组:
pepwfjgg3#
stride()
或多或少是一个具有不同于1的增量的for循环。但是在这里,你想迭代每个元素(即,递增1),并将接下来的n个元素与之一起使用。我发现这个问题很有趣,所以这里有“两个”其他方法。
数组有索引,所以你可以使用它们,有时,我们倾向于忘记它们(关于
indices
值,每次都使用someArray[index]
)。我在第一个解决方案中使用
compactMap()
。这或多或少是一个简单的循环。它的一个小缺点是,如果你的数组有n个元素,它将迭代n次,而不是“n - size”。我在第二个解决方案中使用
map
。它或多或少是一个简单的循环。我计算了before和end,避免了前面的解决方案中不必要的迭代。如果需要的话,你可以把这两种想法结合起来。不清楚如何处理大小限制,如0、size〉count等,所以我保留了日志。
游戏测试:
输出: