【问题标题】:Find nearest key in dictionary using decimal number keys使用十进制数字键在字典中查找最近的键
【发布时间】:2015-05-16 07:47:26
【问题描述】:

我有一些使用datePicker 的快速代码,一旦你点击一个按钮,它就会告诉你当前日期和所选日期之间的年和月的差异,使用小数。

例如:今天是 2015 年 3 月(0.3),在选择器上我选择了 2014 年 12 月。当我点击按钮时,它会正确显示 0.4 或今天与该日期之间的差异。

现在,我的字典中有大约 400 多个键,所有十进制数字为:

var dict: [CGFloat: String] = [5.6: "blabla", 32.4: "bla", etc.]

我如何告诉它检查我点击按钮后得到的数字,在我的情况下是 var completeNumber,(比如说 6.7)是否在字典键中,如果它不去下一个最接近的号码/钥匙?

【问题讨论】:

    标签: swift dictionary key decimal closest


    【解决方案1】:

    字典不会开箱即用,它只会为您提供精确的键匹配。

    但是,由于它是一个集合,如果给定一个距离函数,您可以编写一个搜索可用的最接近匹配的函数。这是一个通用函数:

    (注意我没有花太多时间调试这个,谨慎使用!:)

    /// Search any collection for the index of the closest match, given a 
    /// function to compute the distance between the elements and the target.
    ///
    /// Returns nil in case of an empty collection.
    func findClosestMatchTo<Col: CollectionType, Target, Distance: Comparable>
      (target: Target, within col: Col, #byDistance: (Target,Col.Generator.Element)->Distance) -> Col.Index? 
    {
        var match: Col.Index? = nil
        var bestDistanceSoFar: Distance? = nil
    
        for (idx,elem) in zip(indices(col),col) {
            let thisDistance = byDistance(target, elem)
            if bestDistanceSoFar == nil || thisDistance < bestDistanceSoFar {
                match = idx
                bestDistanceSoFar = thisDistance
            }
        }
    
        return match
    }
    
    /// A convenience version for Strideable types, that can always have their distance computed
    func findClosestMatchTo
      <Col: CollectionType where Col.Generator.Element: Strideable>
      (target: Col.Generator.Element, within col: Col) -> Col.Index? 
    {
        return findClosestMatchTo(target, within: col) { abs($0 - $1) }
    }
    
    // prints 1 (index of 20)
    println(findClosestMatchTo(100, within: [1,20,700,9]))
    // prints 2 (index of 700)
    println(findClosestMatchTo(1000, within: [1,20,700,9]))
    

    现在,您只需编写距离函数,以便比较键/值对的关键部分:

    let dict: [CGFloat: String] = [1: "waffle", 5.6: "blabla", 32.4: "bla"]
    let closest = findClosestMatchTo(5.5, within: dict) { abs($0 - $1.0) }
    if let idx = closest {
        dict[idx]  // prints (5.6, “blabla”)
    }
    

    当然,这个算法相对于字典的大小是 O(n),所以如果你发现自己不断地搜索匹配但很少插入或查找键,你可能想看看不同的数据结构或算法(可能是树或排序数组 + 二分查找)。

    【讨论】:

      【解决方案2】:

      这是我为帮助您入门而编写的一些可怕的代码:

      let items = [1.2: "Cheese", 4.3: "Bacon", 1.5: "Eggs", 8.5: "Toast"]
      
      func findItemCloseTo(value: Double, inItems items: [Double: String]) -> (Double, String)? {
          if items.count == 0 {
              return nil
          }
      
          var foundNumber: Double?
          var foundString: String?
      
          var smallestDistance: Double = Double.infinity
          for (itemKey, itemValue) in items {
              let distance = fabs(itemKey - value)
              if distance < smallestDistance {
                  smallestDistance = distance
                  foundNumber = itemKey
                  foundString = itemValue
              }
          }
      
          return (foundNumber!, foundString!)
      }
      
      findItemCloseTo(1.51, inItems: items) // Return(1.5, Eggs)
      findItemCloseTo(3.0, inItems: items)  // Returns (4.3, Bacon)
      findItemCloseTo(7.0, inItems: items)  // Returns (8.5, Toast)
      

      我认为如果您将数据不存储在字典中而是存储在结构数组中,代码会更简单,例如:

      struct Item {
          var decimalDate: Double
          var data: String
      }
      

      您还可以优化事物并对数组进行排序以加快搜索速度。使用字典,您必须遍历所有项目,因为键不是以任何可预测的排序方式存储的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-20
        • 2010-12-14
        • 1970-01-01
        相关资源
        最近更新 更多