Sort/Filter 键中对象 属性 的字典

Sort/Filter dictionary by property of object in Key

我有一本字典 例如:

let dict = Dictionary<Month, Array<Int32>>()

Obj1.price = "10"
Obj1.value = "abc"
Obj1.title = "January"

Obj2.price = "10"
Obj2.value = "def"
Obj2.title = "April"

Obj3.price = "10"
Obj3.value = "pqr"
Obj3.title = "February"

Obj4.price = "4"
Obj4.value = "mnq"
Obj4.title = "April"

dict = [ Obj1: [3,4], Obj2 : [1,2], Obj3: [8,9], Obj4: [3,3] ]

我有一个自定义的月份数组

let sortTemplate = ["April", "May", "June", "July", "August", "September", "October", "November", "December", "January", "February", "March"]

我想将字典排序为 [ Obj2:[1,2],Obj4:[3,3],Obj1:[3,4],Obj3:[8,9]]

简而言之,我希望根据键 属性 上的自定义引用数组对字典进行排序。 我知道我们不能对字典进行排序,但想根据自定义 sortTemplate 进行排序并插入字典数组

这方面的任何提示都会很有用。 我知道我们可以使用值和键进行排序

这是一个可能的解决方案,它使用 Dictionary 的内置排序功能,但是在您的示例中将 title 属性 作为自定义 enum 而不是String。 "sort template" 然后通过 enum.

中月份的顺序隐式给出

enum MonthSortTemplate 和你的 class MyClass (后者你没有给我们洗澡,所以我自己做了一个 MWE)作为:

enum MonthSortTemplate: Int {
    case April = 1
    case January
    case February
    // ... rest of months follows, in the order you prefer
}

class MyClass {
    var price = ""
    var value = ""
    var title: MonthSortTemplate = .April    
}

// Hashable (just some dummy, don't know how you've set this up)
extension MyClass: Hashable {
    var hashValue: Int {
        return price.hashValue ^ value.hashValue
    }
}

// Equatable (just some dummy, don't know how you've set this up)
func ==(lhs: MyClass, rhs: MyClass) -> Bool {
    return lhs.price == rhs.price && lhs.value == rhs.value
}

创建您的 MyClass 实例,添加到您的字典中,然后将后者的 .sort(...) 函数用于自定义闭包,指定用于此特定类型的比较。

var Obj1 = MyClass()
var Obj2 = MyClass()
var Obj3 = MyClass()

Obj1.price = "10"
Obj1.value = "abc"
Obj1.title = .January

Obj2.price = "10"
Obj2.value = "def"
Obj2.title = .April

Obj3.price = "10"
Obj3.value = "pqr"
Obj3.title = .February

var dict = Dictionary<MyClass, Array<Int32>>()
dict = [ Obj1: [3,4], Obj2 : [1,2], Obj3: [8,9]]

// your custom sort closure, for Dictionary.sort(...) method
let byMonthTemplate = {
    (elem1:(key: MyClass, val: [Int32]), elem2:(key: MyClass, val: [Int32]))->Bool in
    if elem1.key.title.rawValue < elem2.key.title.rawValue {
        return true
    } else {
        return false
    }
}

let sortedDict = dict.sort(byMonthTemplate)
print("\(dict)")

另一种选择---如果你真的喜欢你的 class 属性 title 是类型 String--- 是定义 < MyClass 个对象的运算符:

func <(lhs: MyClass, rhs: MyClass) -> Bool {
    // do comparison stuff with strings lhs.title and rhs.title
    // with regard to your ordering of choice (array sortTemplate)
    return ... 
}

在这种情况下,"messy" 东西最终出现在这个函数中,而实际的排序可以像

一样优雅地执行
let sortedDict = dict.sort { [=13=].0 < .0 }

就个人而言,我更喜欢 enum 解决方案(但是,这是题外话)。


编辑:

应您的要求,我将为您的 class MyClass 添加一个 < 运算符示例。这绝不是最佳选择,但也许您可以根据我的示例对其进行改进。

// add sortTemplate as a static property of MyClass
class MyClass {
    var price = ""
    var value = ""
    var title = "" 
    static let sortTemplate = ["April", "May", "June", "July", "August", "September", "October", "November", "December", "January", "February", "March"]
}

// define < operator for MyClass objects
func <(lhs: MyClass, rhs: MyClass) -> Bool {
    let indexOfLhs = MyClass.sortTemplate.indexOf({[=14=] == lhs.title})
    let indexOfRhs = MyClass.sortTemplate.indexOf({[=14=] == rhs.title})
    return indexOfLhs < indexOfRhs
}

// you can now sort your dictionary according to
let sortedDict = dict.sort { [=14=].0 < .0 }

希望这个帮助,快速而肮脏的方式

let dict = ["Obj1":[3,4],"Obj2":[1,2],"Obj3":[8,9],"Obj4":[3,3]]

let dict1 =  dict.sort { [=10=].1[0] < .1[0]} //Sort by first object in array
let dict2 =  dict1.sort { [=10=].1[1] < .1[1]} //Sort by second object in array

print(dict2)

输出:[("Obj2", [1, 2]), ("Obj4", [3, 3]), ("Obj1", [3, 4]), ("Obj3", [8, 9])]