在Swift中将数组拆分为子数组

Luc*_*tti 11 arrays swift

问题

给定一组值如何将其拆分为由sub-arrays相等的元素组成?

鉴于此数组

let numbers = [1, 1, 1, 3, 3, 4]
Run Code Online (Sandbox Code Playgroud)

我想要这个输出

[[1,1,1], [3, 3], [4]]
Run Code Online (Sandbox Code Playgroud)

我不想要的

解决这个问题的一种可能方法是创建某种索引来指示每个元素的出现.

let indexes = [1:3, 3:2, 4:1]
Run Code Online (Sandbox Code Playgroud)

最后使用索引重建输出数组.

let subsequences = indexes.sort { $0.0.0 < $0.1.0 }.reduce([Int]()) { (res, elm) -> [Int] in
    return res + [Int](count: elm.1, repeatedValue: elm.0)
}
Run Code Online (Sandbox Code Playgroud)

但是,使用此解决方案,我将失去原始值.当然在这种情况下它不是一个大问题(Int值仍然是,Int即使重新创建)但我想将此解决方案应用于更复杂的数据结构,如此

struct Starship: Equatable {
    let name: String
    let warpSpeed: Int
}

func ==(left:Starship, right:Starship) -> Bool {
    return left.warpSpeed == right.warpSpeed
}
Run Code Online (Sandbox Code Playgroud)

最后的考虑

我正在寻找的功能flatten()实际上是某种逆转

let subsequences: [[Int]] = [[1,1,1], [3, 3], [4]]
print(Array(subsequences.flatten())) // [1, 1, 1, 3, 3, 4]
Run Code Online (Sandbox Code Playgroud)

我希望自己明确表示,如果您需要进一步的细节,请告诉我.

Ala*_* T. 19

 // extract unique numbers using a set, then
 // map sub-arrays of the original arrays with a filter on each distinct number

 let numbers = [1, 1, 1, 3, 3, 4]

 let numberGroups = Set(numbers).map{ value in return numbers.filter{$0==value} }

 print(numberGroups)
Run Code Online (Sandbox Code Playgroud)

[编辑]改为使用Hamish建议的Set Initializer

[EDIT2] Swift 4为Dictionary添加了一个初始化程序,可以更有效地执行此操作:

 let numberGroups = Array(Dictionary(grouping:numbers){$0}.values)
Run Code Online (Sandbox Code Playgroud)


ken*_*ytm 5

如果你可以使用 CocoaPods/Carthage/Swift 包管理器等。你可以使用像oisdk/SwiftSequence这样提供group()方法的包:

numbers.lazy.group()
// should return a sequence that generates [1, 1, 1], [3, 3], [4].
Run Code Online (Sandbox Code Playgroud)

UsrNameu1/TraverSwift提供groupBy

groupBy(SequenceOf(numbers), ==)
Run Code Online (Sandbox Code Playgroud)

如果您不想添加外部依赖项,您始终可以编写如下算法:

func group<S: SequenceType where S.Generator.Element: Equatable>(seq: S) -> [[S.Generator.Element]] {
    var result: [[S.Generator.Element]] = []
    var current: [S.Generator.Element] = []
    for element in seq {
        if current.isEmpty || element == current[0] {
            current.append(element)
        } else {
            result.append(current)
            current = [element]
        }
    }
    result.append(current)
    return result
}

group(numbers)
// returns [[1, 1, 1], [3, 3], [4]].
Run Code Online (Sandbox Code Playgroud)