【问题标题】:Array Won't Sort Correctly : Swift 4数组无法正确排序:Swift 4
【发布时间】:2018-01-11 04:31:06
【问题描述】:

我试图对一组自定义对象进行排序,但由于某种原因,几周前有效的代码将不再有效。它应该检查 $0 和 $1 是否具有相同的日期,如果有,它应该按 id 对数组进行排序,但目前它不会正确排序,当我打印数组时,我得到以下输出:

11-07-2017 : 1
11-07-2017 : 10
11-07-2017 : 11
11-07-2017 : 12
11-07-2017 : 13
11-07-2017 : 14
11-07-2017 : 15
11-07-2017 : 16
11-07-2017 : 17
11-07-2017 : 18
11-07-2017 : 19
11-07-2017 : 2
11-07-2017 : 20
11-07-2017 : 3
11-07-2017 : 4
11-07-2017 : 5
11-07-2017 : 7
11-07-2017 : 8
11-07-2017 : 9
11-08-2017 : 1
11-08-2017 : 2
11-09-2017 : 1
11-09-2017 : 2

如上所示,只有少数条目的日期排序正确,但条目较多的日期 (11-07-17) 则不正确。

下面是我的代码:

阵列模型:

struct BalanceUser {

    var id = ""

    var name = ""

    var date = ""

}

当前排序代码:

self.sortedTableArray.sort(by: {
       if $0.date != $1.date {
             return $0.date < $1.date
       } else {
             return $0.id < $1.id
       }
})

Firebase 代码(根据要求):

ref.child("Admin").child("Balances").observeSingleEvent(of: .value, with: { (snapshot) in

        let value = snapshot.value as? NSDictionary

        if value!.count > 1 {

            let specificValues = value?.allKeys

            for balanceUser in specificValues! {

                var user = BalanceUser()

                user.date = balanceUser as! String

                if balanceUser as? String != "balance" {

                    var i = 0

                    var counter = 0

                    while i < 101 {

                        self.ref.child("Admin")
                            .child("Balances")
                            .child(balanceUser as! String)
                            .child(String(i))
                            .observeSingleEvent(of: .value, with: { (snapshot) in

                                let nameValue = snapshot.value as? NSDictionary

                                if nameValue != nil {

                                    user.id = counter

                                    var j = 0

                                    while j < (nameValue?.count)! {

                                        let item = nameValue?.allKeys[j] as? String

                                        var aItem = ""

                                        if let item = nameValue?.allValues[j] as? String {

                                            aItem = item

                                        } else if let item = nameValue?.allValues[j] as? NSNumber {

                                            aItem = String(describing: item)

                                        } else if let item = nameValue?.allValues[j] as? Int {

                                            aItem = String(describing: item)

                                        }


                                        if item == "name" {

                                            user.name = aItem

                                        } else if item == "money" {

                                            user.money = aItem

                                        } else if item == "balance" {

                                            user.balance = aItem

                                        } else if item == "status" {

                                            user.status = aItem

                                        }

                                        j += 1

                                    }


                                    let dateFormatter = DateFormatter()

                                    dateFormatter.dateFormat = "MM-dd-yyyy"

                                    if user.date.components(separatedBy: "-")[0] == dateFormatter.string(from: Date()).components(separatedBy: "-")[0] {

                                        self.sortedTableArray.append(user)

                                        self.sortedTableArray.sort(by: { (object1, object2) -> Bool in

                                            if object1.date == object2.date {

                                                return object1.id < object2.id

                                            } else {

                                                return object1.date < object2.date

                                            }

                                        })

                                    }

                                    self.tableArray.append(user)

                                    self.tableArray.sort(by: { (object1, object2) -> Bool in

                                        if object1.date == object2.date && object1.year == object2.year {

                                            return object2.id > object1.id

                                        } else {

                                            return object1.date < object2.date || object1.year < object2.year

                                        }

                                    })

                                    self.tableView.reloadData()

                                }

                                counter += 1

                            }) { (error) in

                                print(error.localizedDescription)

                        }

                        i += 1

                    }

                }

            }

        } else {

            self.view.makeToast(message: "No Users Found in Database")

        }

    }) { (error) in

        print(error.localizedDescription)

    }

【问题讨论】:

  • 排序正确。您的 id 是字符串,因此它们按字母顺序排序,而不是按数字排序。
  • 哦,我没有意识到这一点。因此,如果我将 id 存储为整数并以这种方式排序,它将正常工作,对吗?
  • 顺便说一句 - 您的日期不会将属性排序为该格式的字符串。它们需要格式化为 yyyy-MM-dd 才能正确排序为字符串。
  • 如果您希望将您的 id 视为数字,则不要使用字符串。使用数值数据类型。或者使用将字符串排序为数字的代码。
  • 不,您的日期排序不正确。添加日期02-15-2018 看看会发生什么。或12-25-2016.

标签: arrays swift sorting swift4


【解决方案1】:

在您编写时它的排序绝对正确。

字符串从一开始就比较每个字符的工作。如果第一个字符相等,则检查第二个,依此类推。 在您的结果“10”

你需要这样比较:

self.sortedTableArray.sort(by: {
   if $0.date != $1.date {
         return $0.date < $1.date
   } else {
         return Int($0.id) ?? 0 < Int($1.id) ?? 0
   }
})

您还应该将日期比较为Date 而不是字符串。

【讨论】:

    【解决方案2】:

    只需使用对数字字符串进行正确排序的字符串比较器

    self.sortedTableArray.sort(by: {
        if $0.date != $1.date {
            return $0.date < $1.date
        } else {
            return $0.id.localizedStandardCompare($1.id) == .orderedAscending
        }
    })
    

    或带有选项.numeric的标准compare选择器

    return $0.id.compare($1.id, options: .numeric) == .orderedAscending
    

    【讨论】:

      【解决方案3】:

      您可以扩展您的 BalanceUser,添加计算属性以返回年、月、日和 id 值。接下来只需使您的结构符合 Comparable 协议:

      extension BalanceUser: Comparable {
          var year: Int {
              return Int(date.suffix(4))!
          }
          var month: Int {
              return Int(date.prefix(2))!
          }
          var day: Int {
              return Int(date.prefix(5).suffix(2))!
          }
          var idValue: Int {
              return Int(id)!
          }
          static func ==(lhs: BalanceUser, rhs: BalanceUser) -> Bool {
              return lhs.date == rhs.date && lhs.id == rhs.id
          }
          static func <(lhs: BalanceUser, rhs: BalanceUser) -> Bool {
              return (lhs.year, lhs.month, lhs.day, lhs.idValue) < (rhs.year, rhs.month, rhs.day, rhs.idValue)
          }
      }
      

      现在您可以简单地对自定义类型数组进行排序:

      sortedTableArray.sort()
      

      【讨论】:

      • 没有任何理由单独比较 == 运算符中的年、月和日。只需按原样比较 dateid
      • @rmaddy 那是真的
      • 元组可用于按多个条件排序,请参阅stackoverflow.com/a/37612765/1187415。 – 在这种情况下:return (lhs.year, lhs.month, lhs.day) &lt; (rhs.year, rhs.month, rhs.day)
      • (lhs.year, lhs.month, lhs.day, lhs.idValue) &lt; (rhs.year, rhs.month, rhs.day, rhs.idValue)
      • GitHub 好像离线了。是的,它是为最多 6 个元组实现的。
      【解决方案4】:

      请检查以下代码:

      let array = ["11-07-2017", "14-07-2017", "10-07-2017","08-07-2017"]
      var convertedArray: [Date] = []
      
      var dateFormatter = DateFormatter()
      dateFormatter.dateFormat = "dd-MM-yyyy"// yyyy-MM-dd"
      
      for dat in array {
          let date = dateFormatter.date(from: dat)
             if let date = date {
                  convertedArray.append(date)
              }
          }
      
      var ready = convertedArray.sorted(by: { $0.compare($1) == .orderedDescending })
      
      print(ready)
      

      【讨论】:

      • 这个答案完全忽略了对 id 部分进行排序的问题,这实际上是导致问题的原因。日期部分排序正确。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-06
      • 2021-07-28
      • 2016-01-11
      • 2012-12-31
      • 2011-09-19
      • 2018-06-03
      相关资源
      最近更新 更多