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

时间:2016-07-22 17:24:50

标签: arrays swift

问题

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

实施例

给定这个数组

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

我想要这个输出

[[1,1,1], [3, 3], [4]]

我不是在寻找

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

let indexes = [1:3, 3:2, 4:1]

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

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)
}

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

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

func ==(left:Starship, right:Starship) -> Bool {
    return left.warpSpeed == right.warpSpeed
}

最后的考虑因素

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

let subsequences: [[Int]] = [[1,1,1], [3, 3], [4]]
print(Array(subsequences.flatten())) // [1, 1, 1, 3, 3, 4]

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

5 个答案:

答案 0 :(得分:15)

 // 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)

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

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

 let numberGroups = Array(Dictionary(grouping:numbers){$0}.values)

对于要按其属性之一分组的对象列表:

 let objectGroups = Array(Dictionary(grouping:objects){$0.property}.values)

答案 1 :(得分:4)

如果你可以使用CocoaPods / Carthage / Swift Package Manager /等。您可以使用提供group()方法的oisdk/SwiftSequence等软件包:

numbers.lazy.group()
// should return a sequence that generates [1, 1, 1], [3, 3], [4].
提供groupBy

UsrNameu1/TraverSwift

groupBy(SequenceOf(numbers), ==)

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

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]].

答案 2 :(得分:1)

假设你有一个未排序的项目数组。你需要对初始数组进行排序,然后你会得到这样的结果: [1, 1, 1, 3, 3, 4]

之后,您将初始化两个数组:一个用于存储数组,另一个用于将其用作当前数组。

循环遍历初始数组并:

  • 如果当前值与最后一个值没有差异,则将其推送到当前数组
  • 否则将当前数组推送到第一个数组,然后清空当前数组。

希望它有所帮助!

答案 3 :(得分:0)

这里kennytm's algorithm是Swift 5的序列扩展:

extension Sequence where Iterator.Element: Equatable {

    func groupedElements() -> [[Iterator.Element]] {
        var result: [[Iterator.Element]] = []
        var current: [Iterator.Element] = []
        for element in self {
            if current.isEmpty || element == current[0] {
                current.append(element)
            } else {
                result.append(current)
                current = [element]
            }
        }
        result.append(current)
        return result
    }

}

答案 4 :(得分:0)

值得一提的是,使用 Swift Algorithms 现在是单行:

import Algorithms
let numbers = [1, 1, 1, 3, 3, 4]
let chunks: [[Int]] = numbers.chunked(by: ==).map { .init($0) }
print(chunks) // [[1, 1, 1], [3, 3], [4]]