繁体   English   中英

筛选和排序快速字典数组

[英]Filter and sort swift array of dictionaries

我有以下数组:

let parent = [ ["Step":"S 3", "Desc":"Do third step" ],
               ["Step":"S 1", "Desc":"Do first step" ],
               ["Step":"S 2", "Desc":"Do second step" ],
                ["Step":"P 1", "Desc":"Some other thing" ] ]

如何以最少的步骤过滤和排序数组(使用过滤器和排序函数),以便获得以下输出字符串或标签——

1.做第一步

2.做第二步

3.做第三步

我建议过滤、排序、枚举、映射和加入:

let results = parent
    .filter { $0["Step"]?.first == "S" }
    .sorted { $0["Step"]!.compare($1["Step"]!, options: .numeric) == .orderedAscending }
    .enumerated()
    .map { (index, value) in "\(index + 1). \(value["Desc"]!)" }
    .joined(separator: "\n")

一个关键的考虑因素是使用.numeric比较,以便“S 10”出现在“S 9”之后,而不是“S 1”和“S 2”之间。 如果您在字符串中嵌入一个数值,您不想进行简单的字符串比较。

我还加入了该枚举,因为如果您删除一个项目,您可能希望确保列表中的数字不会仅仅因为Step字符串中的特定编码而跳过某个值。


不相关的是,字典对于这样的事情来说是一个糟糕的模型。 我建议自定义类型:

struct Task {
    enum TaskType {
        case step
        case process    // or whatever "P" is supposed to stand for
    }

    let sequence: Int
    let type: TaskType
    let taskDescription: String
}

let parent = [Task(sequence: 3, type: .step, taskDescription: "Do third step"),
              Task(sequence: 1, type: .step, taskDescription: "Do first step"),
              Task(sequence: 2, type: .step, taskDescription: "Do second step"),
              Task(sequence: 3, type: .process, taskDescription: "Some other thing")]

let results = parent
    .filter { $0.type == .step }
    .sorted { $0.sequence < $1.sequence }
    .map { "\($0.sequence). \($0.taskDescription)" }
    .joined(separator: "\n")

描述的答案:

首先,您需要过滤数组以仅获取步骤; 根据发布的parent数组,有效步骤似乎应该包含一个键为“Step”和一个格式为“S#”的值,因此它可以被过滤为:

let filtered = parent.filter { (currentDict) -> Bool in
    // get the value for key "Step"
    guard let value = currentDict["Step"] else {
        return false
    }

    // check ifthe value matches the "S #"
    let trimmingBySpace = value.components(separatedBy: " ")
    if trimmingBySpace.count != 2 || trimmingBySpace[0] != "S" || Int(trimmingBySpace[1]) == nil {
        return false
    }

    return true
}

到目前为止会得到:

[["Step": "S 3", "Desc": "Do third step"],
 ["Step": "S 1", "Desc": "Do first step"],
 ["Step": "S 2", "Desc": "Do second step"]]

其次,您将按“Step”键的值对filtered数组进行排序:

let sorted = filtered.sorted { $0["Step"]! < $1["Step"]! }

你应该得到:

[["Step": "S 1", "Desc": "Do first step"],
 ["Step": "S 2", "Desc": "Do second step"],
 ["Step": "S 3", "Desc": "Do third step"]]

最后,您将映射已sorted数组以获取描述值:

let descriptions = sorted.map { $0["Desc"] ?? "" }

descriptions应该是:

["Do first step", "Do second step", "Do third step"]

一步到位:

let result = parent.filter { (currentDict) -> Bool in
    // get the value for key "Step"
    guard let value = currentDict["Step"] else {
        return false
    }

    // check ifthe value matches the "S #"
    let trimmingBySpace = value.components(separatedBy: " ")
    if trimmingBySpace.count != 2 || trimmingBySpace[0] != "S" || Int(trimmingBySpace[1]) == nil {
        return false
    }

    return true
    }.sorted {
    $0["Step"]! < $1["Step"]!
}.map {
    $0["Desc"] ?? ""
}

print(result) // ["Do first step", "Do second step", "Do third step"]
func sortStep(step1:[String:String], step2:[String:String]) -> Bool {
    guard let s1 = step1["Desc"], let s2 = step2["Desc"] else {
    return false
}
    return s1 < s2
}

let orderedStep = parent.sorted { sortStep(step1:$0, step2:$1) }
print("\(orderedStep)")

我使用了强制展开假设您的结构将保持如上所述。 随意根据需要添加任何检查。

parent.filter { $0["Step"]!.contains("S") }.sorted { $0["Step"]! < $1["Step"]!
}.map { print($0["Desc"]!) }
let sorted = parent.filter({ ($0["Step"]?.hasPrefix("S"))! }).sorted { $0["Step"]! < $1["Step"]!}
var prefix = 0
let strings = sorted.reduce("") { (partial, next) -> String in
   prefix += 1
   return partial + "\(prefix)." + next["Desc"]! + "\n"
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM