由某些属性组合数组的元素

Ale*_*y K 12 arrays grouping data-structures swift

我有一个带属性的对象数组date.

我想要的是创建数组数组,其中每个数组将包含具有相同日期的对象.

我明白,我需要像.filter过滤对象一样,然后.map将所有东西添加到数组中.

但是如何告诉.map我需要从过滤对象中为每个组分别使用单独的数组,并且必须将此数组添加到"全局"数组以及如何告诉.filter我需要具有相同日期的对象?

gol*_*tya 13

它可能会迟到但新的Xcode 9 sdk字典有新的init方法

init<S>(grouping values: S, by keyForValue: (S.Element) throws -> Key) rethrows where Value == [S.Element], S : Sequence
Run Code Online (Sandbox Code Playgroud)

文档具有此方法的简单示例. 我只是发布以下示例:

let students = ["Kofi", "Abena", "Efua", "Kweku", "Akosua"]
let studentsByLetter = Dictionary(grouping: students, by: { $0.first! })
Run Code Online (Sandbox Code Playgroud)

结果将是:

["E": ["Efua"], "K": ["Kofi", "Kweku"], "A": ["Abena", "Akosua"]]
Run Code Online (Sandbox Code Playgroud)


Cœu*_*œur 9

改进oriyentel解决方案以允许对任何事物进行有序分组:

extension Sequence {
    func group<GroupingType: Hashable>(by key: (Iterator.Element) -> GroupingType) -> [[Iterator.Element]] {
        var groups: [GroupingType: [Iterator.Element]] = [:]
        var groupsOrder: [GroupingType] = []
        forEach { element in
            let key = key(element)
            if case nil = groups[key]?.append(element) {
                groups[key] = [element]
                groupsOrder.append(key)
            }
        }
        return groupsOrder.map { groups[$0]! }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后它将适用于任何元组,结构以及任何属性:

let a = [(grouping: 10, content: "a"),
         (grouping: 20, content: "b"),
         (grouping: 10, content: "c")]
print(a.group { $0.grouping })

struct GroupInt {
    var grouping: Int
    var content: String
}
let b = [GroupInt(grouping: 10, content: "a"),
         GroupInt(grouping: 20, content: "b"),
         GroupInt(grouping: 10, content: "c")]
print(b.group { $0.grouping })
Run Code Online (Sandbox Code Playgroud)


Ima*_*tit 9

Dictionary使用 Swift 5,您可以使用 的初始值设定项将数组元素按其属性之一分组到字典中init(grouping:by:)Dictionary完成后,您可以使用 的属性values和初始值设定项从字典创建数组的数组Array init(_:)


以下 Playground 示例代码展示了如何按一个属性将数组的元素分组到一个新的数组数组中:

import Foundation

struct Purchase: CustomStringConvertible {
    let id: Int 
    let date: Date
    var description: String {
        return "Purchase #\(id) (\(date))"
    }
}

let date1 = Calendar.current.date(from: DateComponents(year: 2010, month: 11, day: 22))!
let date2 = Calendar.current.date(from: DateComponents(year: 2015, month: 5, day: 1))!
let date3 = Calendar.current.date(from: DateComponents(year: 2012, month: 8, day: 15))!
let purchases = [
    Purchase(id: 1, date: date1),
    Purchase(id: 2, date: date1),
    Purchase(id: 3, date: date2),
    Purchase(id: 4, date: date3),
    Purchase(id: 5, date: date3)
]

let groupingDictionary = Dictionary(grouping: purchases, by: { $0.date })
print(groupingDictionary)
/*
 [
    2012-08-14 22:00:00 +0000: [Purchase #4 (2012-08-14 22:00:00 +0000), Purchase #5 (2012-08-14 22:00:00 +0000)],
    2010-11-21 23:00:00 +0000: [Purchase #1 (2010-11-21 23:00:00 +0000), Purchase #2 (2010-11-21 23:00:00 +0000)],
    2015-04-30 22:00:00 +0000: [Purchase #3 (2015-04-30 22:00:00 +0000)]
 ]
 */

let groupingArray = Array(groupingDictionary.values)
print(groupingArray)
/*
 [
    [Purchase #3 (2015-04-30 22:00:00 +0000)],
    [Purchase #4 (2012-08-14 22:00:00 +0000), Purchase #5 (2012-08-14 22:00:00 +0000)],
    [Purchase #1 (2010-11-21 23:00:00 +0000), Purchase #2 (2010-11-21 23:00:00 +0000)]
 ]
 */
Run Code Online (Sandbox Code Playgroud)


Rap*_*ael 2

抽象一个步骤,您想要的是通过某个属性对数组的元素进行分组。您可以让地图为您进行分组,如下所示:

protocol Groupable {
    associatedtype GroupingType: Hashable
    var grouping: GroupingType { get set }
}

extension Array where Element: Groupable  {
    typealias GroupingType = Element.GroupingType

    func grouped() -> [[Element]] {
        var groups = [GroupingType: [Element]]()

        for element in self {
            if let _ = groups[element.grouping] {
                groups[element.grouping]!.append(element)
            } else {
                groups[element.grouping] = [element]
            }
        }

        return Array<[Element]>(groups.values)
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这种分组是稳定的,即组按出现的顺序出现,并且组内各个元素的出现顺序与原始数组中的顺序相同。

使用示例

我将给出一个使用整数的例子;应该清楚如何使用任何(可哈希)类型T,包括Date.

struct GroupInt: Groupable {
    typealias GroupingType = Int
    var grouping: Int
    var content: String
}

var a = [GroupInt(grouping: 1, content: "a"),
         GroupInt(grouping: 2, content: "b") ,
         GroupInt(grouping: 1, content: "c")]

print(a.grouped())
// > [[GroupInt(grouping: 2, content: "b")], [GroupInt(grouping: 1, content: "a"), GroupInt(grouping: 1, content: "c")]]
Run Code Online (Sandbox Code Playgroud)