【问题标题】:Filter and sort swift array of dictionaries过滤和排序快速的字典数组
【发布时间】:2018-09-22 23:15:37
【问题描述】:

我有以下数组:

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.做第三步

【问题讨论】:

    标签: ios swift filter swift4


    【解决方案1】:

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

    parent.filter { $0["Step"]!.contains("S") }.sorted { $0["Step"]! < $1["Step"]!
    }.map { print($0["Desc"]!) }
    

    【讨论】:

      【解决方案2】:
      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"
      }
      

      【讨论】:

        【解决方案3】:
        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)")
        

        【讨论】:

          【解决方案4】:

          描述的答案:

          首先,您需要过滤数组以仅获取步骤;根据发布的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"]
          

          【讨论】:

            【解决方案5】:

            我建议过滤、排序、枚举、映射和连接:

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

            【讨论】:

            • 我喜欢你讨论数字比较和枚举的案例。
            猜你喜欢
            • 2020-11-12
            • 1970-01-01
            • 1970-01-01
            • 2015-10-27
            • 2017-05-10
            • 1970-01-01
            • 1970-01-01
            • 2014-09-11
            • 1970-01-01
            相关资源
            最近更新 更多