Geohash
Geohashes[1] are used to represent standard latitude and longitude coordinates as single values in the form of a simple string -- using the digits (0-9) and the letters (B-Z excluding I, L, O). They can vary in length, with more characters in the string representing more precision.
- Task
Generate a Geohash with a desired precision from a coordinate represented as an array of two doubles, latitude and longitude.
- Example 1:
- print (encodeGeohash (for: [51.433718, -0.214126], withPrecision: 2))
- // Result: "gc" (all of Ireland, most of England and Wales, small part of Scotland)
- Example 2:
- print (encodeGeohash (for: [51.433718, -0.214126], withPrecision: 9))
- // Result: "gcpue5hp4" (the umpire's chair on Center Court at Wimbledon)
From the Wikipedia page, geohashes can be "useful in database systems where queries on a single index are much easier or faster than multiple-index queries."
Swift
<lang Swift>let gBase32 = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "b", "c", "d", "e", "f", "g", "h", "j", "k", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
func encodeGeohash (for location: Array<Double>, withPrecision precision: Int = 9) -> String {
var latitudeRange = -90.0...90.0 var longitudeRange = -180...180.0
var hash = "" var hashVal = 0 var bits = 0 var even = true
while (hash.count < precision) { let val = even ? location[1]: location[0] var range = even ? longitudeRange : latitudeRange let mid = (range.lowerBound + range.upperBound) / 2
if (val > mid) { hashVal = (hashVal << 1) + 1 range = mid...range.upperBound
if even { longitudeRange = mid...longitudeRange.upperBound } else { latitudeRange = mid...latitudeRange.upperBound } } else { hashVal = (hashVal << 1) + 0 if even { longitudeRange = longitudeRange.lowerBound...mid } else { latitudeRange = latitudeRange.lowerBound...mid } }
even = !even
if (bits < 4) { bits += 1 } else { bits = 0 hash += gBase32[hashVal] hashVal = 0 } } return hash
}