在Swift 4中按属性分组项目

时间:2018-02-16 16:44:53

标签: swift

我的数据来源是

  

{“events”:[{“name”:“event   富 “ ”日期“: ”2018年7月21日“, ”时间“: ”7:00“, ”am_or_pm“: ”PM“, ”天“: ”星期六“, ”说明“:” 测试   “},{”name“:”event   酒吧”, “日期”: “2018年7月21日”, “时间”: “7:00”, “am_or_pm”: “PM”, “天”: “星期六”, “说明”: “TEST2”},   {“名”:“事件   foob​​ar的”, “日期”: “2018年7月21日”, “时间”: “11:00”, “am_or_pm”: “PM”, “天”: “星期六”, “说明”: “TEST3”}] }

我尝试过字典/数组,但并没有真正接近我想要的结果。

将数据拉入数组:

var times = ["9:00","9:00","11:00"]

var names = ["event foo","event bar","event foobar"]

期望的输出:

["9:00", "11:00"]

[["event foo", "event bar"], ["event foobar"]]

任何指向在Swift中执行此操作的指标都表示赞赏。我的最终结果是希望按时间划分一个uitableview。

2 个答案:

答案 0 :(得分:1)

我建议使用Decodable解码JSON,并从组件创建完整日期。然后使用Dictionary(grouping:by:)对数组进行分组。

首先创建一个DateFormatter(如果您需要绝对的UTC日期,请取消注释时区行)

let dateFormatter : DateFormatter = {
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "en_US_POSIX")
    // formatter.timeZone = TimeZone(secondsFromGMT: 0)!
    formatter.dateFormat = "yyyy-MM-dd hh:mm a"
    return formatter
}()

为根元素和events数组创建两个结构。自定义初始值设定项会创建Date实例

struct Root : Decodable {
    let events : [Event]
}

struct Event : Decodable {
    let date : Date
    let name, description : String

    private enum CodingKeys: String, CodingKey { case name, date, time, am_or_pm, description}

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        description = try container.decode(String.self, forKey: .description)
        let datePortion = try container.decode(String.self, forKey: .date)
        let timePortion = try container.decode(String.self, forKey: .time)
        let ampm = try container.decode(String.self, forKey: .am_or_pm)
        let dateString = "\(datePortion) \(timePortion) \(ampm)"
        guard let fullDate = dateFormatter.date(from: dateString) else {
            throw DecodingError.dataCorruptedError(forKey: .date,
                                                   in: container,
                                                   debugDescription: "Date cannot be created")
        }
        date = fullDate
    }
}

解码JSON并将数组分组

let jsonString = """
{"events": [{"name":"event foo","date":"2018-07-21","time":"7:00","am_or_pm":"PM","day":"Saturday","description":"test "}, {"name":"event bar","date":"2018-07-21","time":"7:00","am_or_pm":"PM","day":"Saturday","description":"test2"}, {"name":"event foobar","date":"2018-07-21","time":"11:00","am_or_pm":"PM","day":"Saturday","description":"test3"}]}
"""

do {
    let data = Data(jsonString.utf8)
    let decoder = JSONDecoder()
    let result = try decoder.decode(Root.self, from: data)
    let grouped = Dictionary(grouping: result.events, by: { $0.date})
    print(grouped)
} catch {
    print("error: ", error)
}

答案 1 :(得分:1)

如果使用Swift 4,您可以使用<ItemsControl> <ItemsControl.ItemsPanel> <!-- Grid with rows & columns ... --> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Grid.Row="4" Grid.Column="2" ... /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 和下标运算符的reduce(into:)值:

default

这导致字典:

  

[“11:00”:[“event foobar”],“7:00”:[“event foo”,“event bar”]]

或者,正如Vadian建议的那样,您可以使用guard let json = (try? JSONSerialization.jsonObject(with: data)) as? [String: [Any]], let events = json["events"] as? [[String: String]] else { return } let results = events.reduce(into: [String: [String]]()) { result, value in guard let time = value["time"], let name = value["name"] else { return } result[time, default: []].append(name) } ,但如果您只需要Dictionary(grouping:,by:)值,则必须map,从而产生一系列元组:

name
  

[(“11:00”,[“foobar”事件]),(“7:00”,[“event foo”,“event bar”])]

就个人而言,就像Vadian建议的那样,我倾向于将let results = Dictionary(grouping: events, by: { $0["time"]! }) .map { ($0.key, $0.value.map { $0["name"]! })} datetime结合起来构建一个完整的am_or_pm对象并使用上述其中一个图案。 E.g:

Date

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd h:mm a"
formatter.locale = Locale(identifier: "en_US_POSIX")

// if date/time values are in GMT, uncomment the following line:
//
// formatter.timeZone = TimeZone(secondsFromGMT: 0)

let results = events.reduce(into: [Date: [String]]()) { result, value in
    guard
        let timeString = value["time"],
        let dateString = value["date"],
        let amPm = value["am_or_pm"],
        let date = formatter.date(from: dateString + " " + timeString + " " + amPm),
        let name = value["name"] else { return }
    result[date, default: []].append(name)
}

或者,如果Web服务在JSON中返回了日期,时间和上午/下午的单个ISO 8601 / RFC 3339字符串表示,则可以进一步简化。