【问题标题】:How to access the next key in a Swift dictionary?如何访问 Swift 字典中的下一个键?
【发布时间】:2015-05-27 03:05:05
【问题描述】:

我有这个代码

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

如何访问字典中的下一个键(例如 myDict[k + 1])?

提前致谢!

【问题讨论】:

  • 鉴于字典中键的顺序是不确定的,你想达到什么目的?

标签: swift dictionary nsdictionary


【解决方案1】:

没有“下一个键”之类的东西;字典没有顺序。

但是,由于您正在遍历字典...

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

我将假设您的意思是:我怎么知道在这个迭代中,k下一个迭代中会是什么?

一个简单的解决方案是将字典强制为一个数组(键值元组):

let arr = Array(myDict)

现在你有了整数索引。所以你可以这样枚举它:

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)")
    }
}

当然,事实是,您可以直接枚举字典,但索引不是整数,因此使用起来有点困难。 Martin R 还展示了一种方法来说明这一点。

【讨论】:

  • 谢谢@matt!那行得通,你是对的,很抱歉没有更具体。我确实想知道在这次迭代中,下一次迭代中的 k 会是多少
【解决方案2】:

我不知道这是否是您正在寻找的,但您可以 以与迭代“相似”的方式遍历字典 通过使用DictionaryIndex&lt;Key, Value&gt; 作为索引的数组:

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)")
    }
}

示例输出:

当前键:bar,当前值:2 下一个键:baz,下一个值:3 当前键:baz,当前值:3 下一个键:foo,下一个值:1 当前键:foo,当前值:1

【讨论】:

  • advance(idx, 1) 或:idx.successor()
  • for var idx = dict.startIndex ; idx != dict.endIndex ; idx++ 或:for idx in dict.startIndex..&lt;dict.endIndex
  • 我也发现indices(dict)dict.startIndex..&lt;dict.endIndex 更好
  • @AirspeedVelocity:确实,我忘记了这一点。 (这还是我的答案吗?)
【解决方案3】:

一种可能的解决方案是创建Generator,它按顺序返回当前值和先前值。为此,您需要一个自定义的Generator,它将返回一个元组,其中包含来自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
    }
}

然后将PairGenerator 存储在一个PairSequence 中,它符合SequenceType;这意味着您可以在 for 循环中对其进行迭代。

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

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

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

现在您需要一个函数,该函数将从符合SequenceType 的对象创建PairSequence

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

最后,你可以这样使用:

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

您可以使用pairs(myDict),但就像@Martin R 和@matt 所说的那样 - 字典没有顺序,因此您可能无法按预期顺序获得结果。

有关SequenceTypeGeneratorType 的更多信息,我建议查看Playing With SwiftGenerators In Swift


或者,正如@Martin R 在他的评论中指出的那样,您可以使用:

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

【讨论】:

  • 除非我弄错了,否则zip(values, dropFirst(values)) 会给出与您的pairs(values) 相同的序列。
  • 谢谢,我不知道。这肯定要简单得多!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-01
  • 2022-01-25
相关资源
最近更新 更多