如何正确排序数值属性上的对象数组

时间:2018-03-14 16:48:46

标签: arrays swift sorting format

我有一个像这样的对象数组,但有16个属性:

class anObject: NSObject {
   @objc var number: Int
   @objc var name: String
   @objc var price: Double

   subscript(key: String) -> Any? {
       return self.value(forKey: key)
   }
}

我可以很容易地在任何属性上对数组进行排序,例如:

sortedArray = unsortedArray.sorted(by: { $0.name < $1.name } )

现在我正在对我的数组进行分组,以便我可以使用节和行填充UITableView。我这样分组:

var groupedArray = Dictionary<String, Array<myObject>>()

for item in myArray {
    // Verify each grouping is initialized only once    
    if groupedArray[item[byProperty] as! String] == nil {
        groupedArray[item[byProperty] as! String] = Array<Items>()
    }

    // Add the item into the correct subarray
    groupedArray[item[byProperty] as! String]?.append(item)
}

然后,我可以通过执行以下操作对分组数组进行排序:

return groupedArray.sorted { $0.0 < $1.0 }

这很有效,除了我的两个属性是双打。当我对这两个属性进行排序时,Swift按字母顺序对组进行排序:

10.5, 11.5, 12, 1.5, 2.0 . . .

而不是数字

1.5, 2.0, 10.5, 11.5, 12 . . . 

我设法通过检查它们是否太短并在String的前面插入0来填充双打。这样做的原因在于它们现在按正确的顺序排序,但最终我将不得不从前面剥离前导0,这似乎是一个丑陋的解决方案。

如果双打必须用作字符串,我如何正确对分组数组进行排序?

2 个答案:

答案 0 :(得分:0)

当您开始在整个地方投射字符串时,您可能需要开始更改设计。为什么不使字典键成为你设计的对象而不是字符串呢?这是我的意思的样本:

struct DoubleKey {
    let value: Double
}
extension DoubleKey: Hashable {
    var hashValue: Int {
        return value.hashValue
    }

    static func ==(lhs: DoubleKey, rhs: DoubleKey) -> Bool {
        return lhs.value == rhs.value
    }
}
extension DoubleKey: Comparable {
    static func <(lhs: DoubleKey, rhs: DoubleKey) -> Bool {
        return lhs.value < rhs.value
    }
}

let a = DoubleKey(value: 10.0)
let b = DoubleKey(value: 20.0)
let c = DoubleKey(value: -10.0)
let dictionary: [DoubleKey: String] = [a: "10", b: "20", c: "-10"]
let sortedDictionary = dictionary.sorted { $0.0 < $1.0 }

因此,[String: Array<myobject>][DoubleKey: Array<MyObject>[IntegerKey: Array<MyObject>]

代替[StringKey: Array<MyObject>

您可以实现自己专用密钥的许多变体,并在需要其他功能时编写一些协议。如果你需要在你的密钥中存储一个字符串,那么添加一个属性,或者更好的是,使它符合一个协议,该协议定义你需要的行为并实现它。

附加密钥

struct StringKey {
    let value: String
}
extension StringKey: Hashable {
    var hashValue: Int {
        return value.hashValue
    }

    static func ==(lhs: StringKey, rhs: StringKey) -> Bool {
        return lhs.value == rhs.value
    }
}
extension StringKey: Comparable {
    static func <(lhs: StringKey, rhs: StringKey) -> Bool {
        return lhs.value < rhs.value
    }
}

let a = StringKey(value: "a")
let b = StringKey(value: "c")
let c = StringKey(value: "b")
let dictionary: [StringKey: String] = [a: "10", b: "20", c: "-10"]
let sortedDictionary = dictionary.sorted { $0.0 < $1.0 }

现在是什么?

//EXAMPLE
protocol ViewableString {
    func view() -> String
}

extension StringKey: ViewableString {
    func view() -> String {
        return value
    }
}

extension DoubleKey: ViewableString {
    func view() -> String {
        return String(value)
    }
}

let array: [ViewableString] = [a, b, c]
array[0].view()

编写协议程序!

希望这有帮助!

答案 1 :(得分:0)

确定。完全不同的答案。同样,您试图在同一容器中容纳不同类型的许多对象。这对我来说是一个坏主意。也许你必须这样做。但这是使用枚举的一种方式:

enum SpecialKey {
    case integer(Int)
    case double(Double)
    case string(String)

    func asString() -> String {
        switch self {
            case let .integer(a):
                return String(a)
            case let .double(a):
                return String(a)
            case let .string(a):
                return a
        }
    }
}
extension SpecialKey: Comparable {
    static func <(lhs: SpecialKey, rhs: SpecialKey) -> Bool {
        switch (lhs, rhs) {
        case let (.double(a), .double(b)):
            return a < b
        case let (.integer(a), .integer(b)):
            return a < b
        case let (.string(a), .string(b)):
            return a < b
        default:
            return false //Add more cases with different comparisons!
        }
    }

    static func ==(lhs: SpecialKey, rhs: SpecialKey) -> Bool {
        switch (lhs, rhs) {
            case (.integer(_), .integer(_)),
                 (.double(_), .double(_)),
                 (.string(_), .string(_)):
                return true
            default:
                return false
        }
    }
}

extension SpecialKey: Hashable {
    var hashValue: Int {
        switch self {
        case let .integer(a):
            return a.hashValue
        case let .double(a):
            return a.hashValue
        case let .string(a):
            return a.hashValue
        }
    }
}

let a = SpecialKey.integer(10)
let b = SpecialKey.string("something")
let c = SpecialKey.double(10.5)
let dictionary: [SpecialKey: String] = [a: "a", b: "b", c: "c"]

这可能更像你正在寻找的东西。