How to access the next key in a Swift dictionary?

久未见 提交于 2020-01-05 22:57:12

问题


I have this code

for (k, v) in myDict {
    println(k)
}

How do I access the next key in the dictionary (e.g. myDict[k + 1])?

Thanks in advance!


回答1:


There is no such thing as "the next key"; dictionaries have no order.

Since, however, you are iterating through the dictionary...

for (k, v) in myDict {
    println(k)
}

I'm going to assume that what you mean is: how can I know, on this iteration, what k would be on the next iteration?

A simple solution would be to coerce the dictionary to an array (of key-value tuples):

let arr = Array(myDict)

Now you have something with integer indexes. So you can enumerate it like this:

let arr = Array(myDict)
for (ix, (k,v)) in enumerate(arr) {
    println("This key is \(k)")
    if ix < arr.count-1 {
        println("The next key is \(arr[ix+1].0)")
    }
}

The truth is, of course, that you can enumerate a dictionary directly, but indexes are not integers, so they are a little harder to work with. Martin R is also showing an approach illustrating that point.




回答2:


I don't know if this is what you are looking for, but you can iterate through a dictionary in a "similar" way as iterating through an array by using the DictionaryIndex<Key, Value> as an index:

let dict = [ "foo" : 1, "bar" : 2, "baz" : 3]

for idx in indices(dict) {

    let (k, v) = dict[idx]
    println("Current key: \(k), current value: \(v)")

    let nextIdx = idx.successor()
    if nextIdx != dict.endIndex {
        let (k1, v1) = dict[nextIdx]
        println("Next key: \(k1), next value: \(v1)")
    }
}

Sample output:

Current key: bar, current value: 2
Next key: baz, next value: 3
Current key: baz, current value: 3
Next key: foo, next value: 1
Current key: foo, current value: 1



回答3:


A possible solution is to create Generator which returns the current and previous values in a sequence. For this you need a custom Generator which will return a tuple, containing the previous and current values from a sequence, from next:

struct PairGenerator<Base: GeneratorType> : GeneratorType {
    typealias ElementPair = (previousElement: Base.Element, currentElement: Base.Element)

    private var base: Base
    private var previousElement: Base.Element?

    init(_ base: Base) {
        self.base = base
    }

    mutating func next() -> ElementPair? {
        if previousElement == nil { previousElement = base.next() }
        let currentElement = base.next()

        // Since `base.next()` returns `nil` when the end of the sequence
        // is reached, we need to check `previousElement` and `currentElement ` 
        // aren't `nil`. If either of them are, `nil` will be returned to signal
        // there aren't any pairs left.
        if let prev = previousElement, curr = currentElement {
            previousElement = currentElement
            return (prev, curr)
        }

        return nil
    }
}

The PairGenerator is then stored in a PairSequence, which conforms to SequenceType; this means you can iterate over it in a for loop.

struct PairSequence<Base: SequenceType> : SequenceType {
    let generator: PairGenerator<Base.Generator>

    init(_ base: Base) {
        generator = PairGenerator(base.generate())
    }

    func generate() -> PairGenerator<Base.Generator> {
        return generator
    }
} 

Now you need a function which will create a PairSequence from an object that conforms to SequenceType:

func pairs<Seq: SequenceType>(base: Seq) -> PairSequence<Seq> {
    return PairSequence(base)
}

Finally, you can use this like so:

let myDict = ["1": 1, "2": 2, "3": 3, "4": 4]
let values = Array(myDict.values).sorted(<)

for (prev, curr) in pairs(values) {
    println("\(prev), \(curr)")
}

// Prints:
// 1, 2
// 2, 3
// 3, 4

You could use pairs(myDict), but like @Martin R and @matt said - Dictionaries don't have an order so you may not get the results in the order you expected.

For more information on SequenceType and GeneratorType, I'd recommend looking at Playing With Swift and Generators In Swift.


Or, as @Martin R pointed out in his comment, you could use:

for (prev, curr) in zip(values, dropFirst(values)) {
    println("\(prev), \(curr)")
}


来源:https://stackoverflow.com/questions/30464861/how-to-access-the-next-key-in-a-swift-dictionary

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!