保持按索引更新的有序字典值数组

时间:2016-01-23 08:47:49

标签: ios swift uitableview

我有一本从另一个班级更新的词典。我在字典上有一个属性观察者,所以我知道何时添加或删除了一个值。

我根据字典的值创建一个排序数组。我需要更新此数组并保留与更新相关联的索引以与UITableView一起使用。我的UI是这样的,无法批量重新加载数据 - 我需要根据更新的内容直接插入或删除行。

我把它简化成了一个游乐场:

func dictionaryUpdated() {

print("dictionary updated")
// Add or remove string at index depending on order.
}

var myDictionary : [Int:String] = ["Bob".hashValue:"Bob","Dave".hashValue:"Dave","Yoda".hashValue:"Yoda","Windu".hashValue:"Windu","Obi Wan".hashValue:"Obi Wan","Qui-gon".hashValue:"Qui-gon","Anakin".hashValue:"Anakin"] { didSet { dictionaryUpdated() } }

func addEntry(entry: String) {

myDictionary[entry.hashValue] = entry
}

func removeEntry(entry: String) {

myDictionary.removeValueForKey(entry.hashValue)
}

// sort the keys alphabetically while creating the array
var valuesArray = myDictionary.values.sort { (lhs, rhs) -> Bool in
return lhs < rhs
}

我尝试过使用NSMutableOrderedSet,但键只能是字符串。

2 个答案:

答案 0 :(得分:1)

只是在操场上玩耍。虽然可以更加优雅......

var valuesArray: [String] = [] { didSet { valuesArray.sortInPlace { $0 < $1 } } }

func dictionaryUpdated(old: [Int: String]) {

    let added = myDictionary.count > old.count
    let item: [String] = added ? myDictionary.values.filter { !old.values.contains($0) } : old.values.filter { !myDictionary.values.contains($0) }

    valuesArray += item

    let index = valuesArray.indexOf(item[0])!

    print("item " + (added ? "added" : "removed") + ": \(item) at index \(index)")
}

var myDictionary: [Int: String] = ["Yoda".hashValue: "Yoda", "Windu".hashValue: "Windu", "Obi Wan".hashValue: "Obi Wan"] {
    didSet {
        dictionaryUpdated(oldValue)
    }
}

addEntry("Darth Vader")
print(valuesArray)

输出:

item added: ["Darth Vader"] at index 0
["Darth Vader", "Obi Wan", "Windu", "Yoda"]

答案 1 :(得分:0)

假设在属性更改之前和之后都有排序数组(可以通过另一个实例变量实现),您需要做的是比较旧数组和新数组,并检测哪些索引发生了变化。

这个问题的一个优雅的解决方案是向diff类添加Array方法来计算差异。该方法可能如下所示:

extension Array where Element: Equatable {
    func diff(other: [Element]) -> (added: [Int], deleted: [Int], moved: [(from: Int, to: Int)]) {
        var added: [Int] = []
        var deleted: [Int] = []
        var moved: [(from: Int, to: Int)] = []
        for (i, item) in enumerate() {
            if let j = other.indexOf({$0 == item}) {
                if i != j {
                    moved.append((from: i, to: j))
                }
            } else {
                deleted.append(i)
            }
        }
        for (i, item) in other.enumerate() {
            if indexOf({$0 == item}) == nil {
                added.append(i)
            }
        }
        return (added: added, deleted: deleted, moved: moved)
    }
}

然后你会这样使用:valuesArray.diff(oldValuesArray)