I was trying to sort an array of custom objects but for some reason, the code that worked a few weeks back won't work anymore. It is supposed to check if 0ドル and 1ドル have the same date, and if they do, it is supposed to sort the array by id, but currently it won't sort correctly and when I print the array, I get the following output:
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
As can be seen above, the dates that only have a few entries sort correctly, but the dates with more entries (11-07-17) don't.
Below is my code:
Model for the Array:
struct BalanceUser {
var id = ""
var name = ""
var date = ""
}
Current Sorting Code:
self.sortedTableArray.sort(by: {
if 0ドル.date != 1ドル.date {
return 0ドル.date < 1ドル.date
} else {
return 0ドル.id < 1ドル.id
}
})
Firebase Code (As Requested):
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)
}
4 Answers 4
It's sorting absolutely correct as you write it.
Strings comparing work for every char from the beginning. If first char is equal then check second and so on. In your results "10" < "2", cause unicode of "1"-character is less then "2"-character code.
You need to compare do it like this:
self.sortedTableArray.sort(by: {
if 0ドル.date != 1ドル.date {
return 0ドル.date < 1ドル.date
} else {
return Int(0ドル.id) ?? 0 < Int(1ドル.id) ?? 0
}
})
Also your should compare dates as Date
not Strings.
Just use the string comparator which sorts numeric strings properly
self.sortedTableArray.sort(by: {
if 0ドル.date != 1ドル.date {
return 0ドル.date < 1ドル.date
} else {
return 0ドル.id.localizedStandardCompare(1ドル.id) == .orderedAscending
}
})
or the standard compare
selector with option .numeric
return 0ドル.id.compare(1ドル.id, options: .numeric) == .orderedAscending
You can extend your BalanceUser adding computed properties to return year, month, day and id value. Next just make your struct conform to Comparable protocol:
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)
}
}
Now you can simply sort your custom type array:
sortedTableArray.sort()
-
Not really any reason to separately compare the year, month, and day in the
==
operator. Just comparedate
andid
as-is.rmaddy– rmaddy2018年01月11日 05:59:24 +00:00Commented Jan 11, 2018 at 5:59 -
-
1Tuples can be used to sort by multiple criteria, see stackoverflow.com/a/37612765/1187415. – In this case:
return (lhs.year, lhs.month, lhs.day) < (rhs.year, rhs.month, rhs.day)
Martin R– Martin R2018年01月11日 06:20:59 +00:00Commented Jan 11, 2018 at 6:20 -
2Or
(lhs.year, lhs.month, lhs.day, lhs.idValue) < (rhs.year, rhs.month, rhs.day, rhs.idValue)
Martin R– Martin R2018年01月11日 06:27:06 +00:00Commented Jan 11, 2018 at 6:27 -
1GitHub seems to be offline. And yes, it is implemented for tuples up to arity 6.Martin R– Martin R2018年01月11日 15:21:40 +00:00Commented Jan 11, 2018 at 15:21
Please check the following code:
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)
-
This answer completely misses the issue of sorting the id part which is what is actually causing the issue. The date part is sorting correctly.Upholder Of Truth– Upholder Of Truth2018年01月11日 09:53:31 +00:00Commented Jan 11, 2018 at 9:53
02-15-2018
and see what happens. Or12-25-2016
.