给定任何类型的数组和想要的子数组数量,我需要这个输出:
print([0, 1, 2, 3, 4, 5, 6].splitInSubArrays(into: 3))
// [[0, 3, 6], [1, 4], [2, 5]]
Run Code Online (Sandbox Code Playgroud)
即使没有“足够”的元素来填充这些,输出也必须包含正确数量的子数组:
print([0, 1, 2].splitInSubArrays(into: 4))
// [[0], [1], [2], []]
Run Code Online (Sandbox Code Playgroud)
我现在有这个工作实现,但有没有更好(更优雅)的方式来实现这个输出:
extension Array {
func splitInSubArrays(into size: Int) -> [[Element]] {
var output: [[Element]] = []
(0..<size).forEach {
var subArray: [Element] = []
for elem in stride(from: $0, to: count, by: size) {
subArray.append(self[elem])
}
output.append(subArray)
}
return output
}
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*n R 15
您可以用一个map()
操作替换两个循环:
extension Array {
func splitInSubArrays(into size: Int) -> [[Element]] {
return (0..<size).map {
stride(from: $0, to: count, by: size).map { self[$0] }
}
}
}
Run Code Online (Sandbox Code Playgroud)
外部map()
将每个偏移量映射到相应的数组,内部map()
将索引映射到数组元素。
例子:
print([0, 1, 2, 3, 4, 5, 6].splitInSubArrays(into: 3))
// [[0, 3, 6], [1, 4], [2, 5]]
print([0, 1, 2].splitInSubArrays(into: 4))
// [[0], [1], [2], []]
Run Code Online (Sandbox Code Playgroud)
只是为了好玩一个也适用于字符串的通用实现:
extension Collection {
func every(n: Int, start: Int = 0) -> UnfoldSequence<Element,Index> {
sequence(state: dropFirst(start).startIndex) { index in
guard index < endIndex else { return nil }
defer { index = self.index(index, offsetBy: n, limitedBy: endIndex) ?? endIndex }
return self[index]
}
}
}
Run Code Online (Sandbox Code Playgroud)
extension RangeReplaceableCollection {
func splitIn(subSequences n: Int) -> [SubSequence] {
(0..<n).map { .init(every(n: n, start: $0)) }
}
}
Run Code Online (Sandbox Code Playgroud)
[0, 1, 2, 3, 4, 5, 6].splitIn(subSequences: 3) // [[0, 3, 6], [1, 4], [2, 5]]
[0, 1, 2].splitIn(subSequences: 4) // [[0], [1], [2], []]
"0123456".splitIn(subSequences: 3) // ["036", "14", "25"]
Run Code Online (Sandbox Code Playgroud)
最直观的方法是非常简单:
所以它真的无非是这样:
arrays[i%n].append(item i)
Run Code Online (Sandbox Code Playgroud)
下面每个@LeoDabus 注释的示例代码
extension RangeReplaceableCollection {
func moduloishtrancheization(n: Int) -> [SubSequence] {
var r: [SubSequence] = .init(repeating: .init(), count: n)
var i = 0
forEach {
r[i%n].append($0)
i += 1
}
return r
}
}
Run Code Online (Sandbox Code Playgroud)
这就是整件事。
'允许它用于所有序列会很好。
stride(from: 0, through: 6, by: 1).splitInSubArrays(into: 3)
Run Code Online (Sandbox Code Playgroud)
(如果它在许多应用程序中有用,也可以将其放入公共扩展程序中,如下所示。)
extension Sequence {
func splitInSubArrays(into size: Int) -> [[Element]] {
enumerated()
.grouped { $0.offset % size }
.map { $0.map(\.element) }
}
}
Run Code Online (Sandbox Code Playgroud)
/// Group the elements by a transformation into an `Equatable`.
/// - Note: Similar to `Dictionary(grouping values:)`,
/// but preserves "key" ordering, and doesn't require hashability.
func grouped<Equatable: Swift.Equatable>(
by equatable: (Element) throws -> Equatable
) rethrows -> [[Element]] {
try reduce(into: [(equatable: Equatable, elements: [Element])]()) {
let equatable = try equatable($1)
if let index = ( $0.firstIndex { $0.equatable == equatable } ) {
$0[index].elements.append($1)
} else {
$0.append((equatable, [$1]))
}
}.map(\.elements)
}
Run Code Online (Sandbox Code Playgroud)
为了完整reduce
起见,这是一个适用于所有Collection
类型的基于 - 的解决方案:
extension Collection {
func splitInSubArrays(_ size: Int) -> [[Element]] {
enumerated().reduce(into: [[Element]](repeating: [], count: size)) {
$0[$1.offset % size].append($1.element)
}
}
}
Run Code Online (Sandbox Code Playgroud)
函数如何工作:它创建一个空的[Element]
条目数组,并将原始数组的每个元素附加到相应的子数组。我们在这里使用 ofreduce
只是为了携带结果数组,以避免显式创建局部变量(尽管内部reduce
为我们这样做)。
用法:
print([0, 1, 2, 3, 4, 5, 6].splitInSubArrays(3)) // [[0, 3, 6], [1, 4], [2, 5]]
print([0, 1, 2].splitInSubArrays(4)) // [[0], [1], [2], []]
print("ABCDEF".splitInSubArrays(3)) // ["A", "D"], ["B", "E"], ["C", "F"]]
Run Code Online (Sandbox Code Playgroud)
请注意,正如 Leo Dabus 所指出的,在上面的最后一个示例中,二维数组不是基于字符串的数组,而是二维字符数组[[Character]]
。改为生成子串数组,RangeReplaceableCollection
可以进行扩展,结果类型可以改为[SubSequence]
.
归档时间: |
|
查看次数: |
851 次 |
最近记录: |