【问题标题】:How do you split a Dictionary into another Dictionaries你如何将一个字典拆分成另一个字典
【发布时间】:2018-01-12 10:16:26
【问题描述】:

考虑到这本词典:

var dict = ["Steve": 17,
             "Marc": 38,
             "Xavier": 21,
             "Rolf": 45,
             "Peter": 67,
             "Nassim" : 87,
             "Raj": 266,
             "Paul": 220,
             "Bill": 392]

我需要创建一个 Category 对象的 3 个新实例:

class Category {
    var name = ""
    var note = 0
}

并使用 var dict 创建此对象的 3 个新实例(即:初级、中级、高级)。

假设我已经知道前 3 个是初级,接下来 3 个是中级,最后 3 个是高级。

谢谢,

【问题讨论】:

  • 你是如何构建你的源代码的?如果是手动完成的,那么最好手动划分它们。
  • 不清楚您期望输出什么。 Category 中的 note 是什么?属于某个类别的 dict 元素存储在哪里?
  • dict 最初来自 JSON,Category 中的注释是值
  • 我觉得这个问题听起来很熟悉。原来也是你昨天问这个的:stackoverflow.com/questions/48208700/…

标签: swift dictionary filter


【解决方案1】:

一般来说,字典是没有顺序的,所以你不能像遍历数组那样遍历它。但你可以这样做:

    let array = [("Steve", 17),
                 ("Marc", 38),
                 ("Xavier", 21),
                 ("Rolf", 45),
                 ("Peter", 67),
                 ("Nassim", 87),
                 ("Raj", 266),
                 ("Paul", 220),
                 ("Bill", 392)]
    var dicts = [[String: Int]]()

    for _ in 0..<3 {
        dicts.append([String: Int]())
    }

    for i in 0..<array.count {
        dicts[i % 3][array[i].0] = array[i].1
    }

【讨论】:

  • 但是每次执行代码,都会在dicts中收到不同的值
  • 你实际上可以遍历字典,但绝对不能保证顺序:for (key, value) in dictionary {}
  • 就像我说的,你不能在数组上迭代 like
【解决方案2】:

我可能会这样定义一个 Worker 类:

enum Seniority {
    case junior, intermediate, senior
}

struct Worker {
    var name: String
    var score: Int
    var seniority: Seniority
}

然后您可以将字典映射到一组工作人员(请注意,您必须使用名称,并且由于 Swift 中的dictionaries have no order 不能使用顺序):

var workers = [Worker]()
for name in dict.keys {
    switch name {
    case "Steve", "Marc", "Xavier": workers += [Worker(name: name, score: dict[name]!, seniority: .junior)]
    case "Rolf", "Peter", "Nassim": workers += [Worker(name: name, score: dict[name]!, seniority: .intermediate)]
    default: workers += [Worker(name: name, score: dict[name]!, seniority: .senior)]
    }
}

例如,您可以使用它检索一个只有高级员工的数组,如下所示:

let seniors = workers.filter { $0.seniority == .senior }

【讨论】:

    【解决方案3】:

    如果您不打算更改输入数据(作业?),这可能就是您想要的:

    import Foundation
    
    var data = ["Steve": 17,
                 "Marc": 38,
                 "Xavier": 21,
                 "Rolf": 45,
                 "Peter": 67,
                 "Nassim" : 87,
                 "Raj": 266,
                 "Paul": 220,
                 "Bill": 392]
    
    
    enum Seniority { case senior, junior, intermediate }
    
    struct Worker {
        let name: String
        let note: Int
    }
    
    struct Category {
        let seniority: Seniority
        let staff: [Worker]
    }
    
    /* the partition is fixed, but at least sort by score to get it */
    let all = data.sorted { (a, b) -> Bool in
        return a.value < b.value
    }
    
    /* let's use some weird variable names to note the absurd of a hardcoded partition */
    let _1_3 = all.prefix(3)
    let _4_6 = all.suffix(from: 3).prefix(3)
    let _7_9 = all.suffix(3)
    
    let junior = Category(seniority: .junior, staff: _1_3.map { Worker(name: $0.key, note: $0.value) })
    let intermediate = Category(seniority: .intermediate, staff: _4_6.map { Worker(name: $0.key, note: $0.value) })
    let senior = Category(seniority: .senior, staff: _7_9.map { Worker(name: $0.key, note: $0.value) })
    

    让我们检查结果类别:

    print(junior.staff.map { "\($0.name) -> \($0.note)" })
    // ["Steve -> 17", "Xavier -> 21", "Marc -> 38"]
    print(intermediate.staff.map { "\($0.name) -> \($0.note)" })
    // ["Rolf -> 45", "Peter -> 67", "Nassim -> 87"]
    print(senior.staff.map { "\($0.name) -> \($0.note)" })
    // ["Paul -> 220", "Raj -> 266", "Bill -> 392"]
    

    原答案:

    如果dict(我将其重命名为staff)中的数字是某种分数:

    import Foundation
    
    var staff = ["Steve": 17,
                "Marc": 38,
                "Xavier": 21,
                "Rolf": 45,
                "Peter": 67,
                "Nassim" : 87,
                "Raj": 266,
                "Paul": 220,
                "Bill": 392]
    

    让我们在它们上定义一个分区:

    let categories: [String:Any] = [
        "junior" : (0...19),
        "intermediate": (20..<100),
        "senior": (100...)
    ]
    

    加上一个函数,用于根据该分区返回给定分数的资历名称:

    func seniority(score: Int) -> String {
        for category in categories {
            if let range = category.value as? CountableRange<Int> {
                if range.contains(score) {
                    return category.key
                }
            }
            else if let range = category.value as? CountableClosedRange<Int> {
                if range.contains(score) {
                    return category.key
                }
            }
            else if let range = category.value as? CountablePartialRangeFrom<Int> {
                if range.contains(score) {
                    return category.key
                }
            }
        }
        fatalError("Defined ranges should cover all possible scores")
    }
    
    assert(seniority(score: staff["Steve"]!) == "junior")
    assert(seniority(score: staff["Xavier"]!) == "intermediate")
    assert(seniority(score: staff["Paul"]!) == "senior")
    

    最后使用分区和定义的函数将原来的staff字典拆分成“n”个新字典:

    var newStaff = Dictionary(uniqueKeysWithValues: zip(categories.keys, 
                              repeatElement([String:Int](), count: categories.count)))
    for (name, score) in staff {
        let category = seniority(score: score)
        newStaff[category]![name] = score
    }
    
    print(newStaff)
    

    我明白了:

    ["intermediate": ["Nassim": 87, "Marc": 38, "Peter": 67, "Rolf": 45, "Xavier": 21], 
     "senior": ["Bill": 392, "Paul": 220, "Raj": 266], 
     "junior": ["Steve": 17]
    ]
    

    您可以根据自己的具体需求轻松调整它。

    【讨论】:

    • 谢谢,但我的需要更容易。我已经知道按字典顺序,前 3 个是初级,接下来 3 个是中级,最后 3 个是高级。我只需要创建 3 个新实例(前 3 个为初级,接下来的 3 个为中级......)
    猜你喜欢
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-27
    • 1970-01-01
    • 2021-09-09
    相关资源
    最近更新 更多