A Dictionary Object That Uses Ranges of Values for Keys

A dictionary object that uses ranges of values for keys

A dictionary is not the appropriate data structure for the operations you are describing.

If the intervals are required to never overlap then you can just build a sorted list of intervals and binary search it.

If the intervals can overlap then you have a more difficult problem to solve. To solve that problem efficiently you'll want to build an interval tree:

http://en.wikipedia.org/wiki/Interval_tree

This is a well-known data structure. See "Introduction To Algorithms" or any other decent undergraduate text on data structures.

How to use a range for dict keys?

range() in Python 2 is merely a function that returns a list of integers, it is not itself a type of object. And you wouldn't want to use lists here, no, because they contain all integers in the range.

You could use xrange() objects instead, these are hashable, and only store the start and end values. However, unless you plan to use other xrange() objects to test these keys, a dictionary with such keys is not very useful, you'd have to loop over the dictionary to test your rate against each xrange object manually.

Your success rate dictionary could more simply be replaced by maths; just round your numbers up to the nearest multiple of 10 (simply using floor division):

success_rate = ((amount_of_urls // 10) + 1) * 10

Do test if that resulting value is between 10 and 100:

10 <= success_rate <= 100

Is it possible to have a range as a key in a Swift Dictionary?

If you insist on using Dictionary, you have to wait until Swift 3.1 (currently in beta):

extension CountableClosedRange : Hashable {
public var hashValue: Int {
return "\(lowerBound) to \(upperBound)".hashValue
}
}

// This feature is called concrete-type extension and requires Swift 3.1
extension Dictionary where Key == CountableClosedRange<Int> {
subscript(rawValue rawValue: Int) -> Value? {
for k in self.keys {
if k ~= rawValue {
return self[k]
}
}

return nil
}
}

let dict : [CountableClosedRange<Int>: String] = [
1...5: "first",
6...10: "second"
]

print(dict[rawValue: 1])
print(dict[rawValue: 2])
print(dict[rawValue: 3])
print(dict[rawValue: 7])
print(dict[rawValue: 8])
print(dict[rawValue: 9])

However, it's a lot clearer if you implement your own data model:

struct MyRange {
var ranges = [CountableClosedRange<Int>]()
var descriptions = [String]()

mutating func append(range: CountableClosedRange<Int>, description: String) {
// You can check for overlapping range here if you want
self.ranges.append(range)
self.descriptions.append(description)
}

subscript(value: Int) -> String? {
for (i, range) in self.ranges.enumerated() {
if range ~= value {
return descriptions[i]
}
}

return nil
}
}

var range = MyRange()
range.append(range: 1...5, description: "one")
range.append(range: 6...10, description: "second")

print(range[1])
print(range[2])
print(range[6])
print(range[7])
print(range[100])

Assign a Range of Numbers to a Single Key with Dictionaries

You have the dictionary backwards. If you want to be able to recall, e.g., 'apple' with any of the numbers 1-5, you'd need the numbers to be the keys, not the values.

for i in range(1,6):  # range(a,b) gives [a,b)
my_dict[i] = 'apple'

etc. Then, my_dict[4] == 'apple' and the same is true for the other values in the range.

This can create very large dictionaries with many copies of the same value.

Alternately, you can use range objects as dictionary keys, but the testing will be a bit more cumbersome unless you create your own class.

my_dict[range(1,6)] = 'apple'
n = random.randint(1, 5)

for key in my_dict:
if n in key:
print(my_dict[key])

...prints apple.

For Looping Over Dictionary Object

data is a dictionary, not a function, so you shouldn't use parenthesis to attempt to access it.

You should also be iterating over data.items(), not len(range(data)). You're iterating over the keys of a dictionary, not a list.

With these two corrections, we get the following:

for key, values in data.items():
ratio = values[0]/values[1]

Strange behavior of range when used as key in dictionary

So here, we have three different values being passed around:

  1. The original range.
  2. Range.Value, which is a variant.
  3. The copy of (1) which is internal to the dictionary.

If you compare these with equal signs, they are all the same. But according to Dictionary.Exists they are all different.

Why? When you use an equal sign with an object, the equal sign forces the object to call its default property. The default property of Range is Range.Value, which is why r = r.Value and also r = r.Offset(0, 0).

But for a dictionary this isn't so smart. Think about it: Every call to Dictionary.Exists would cause every object used as a key to call its default property. This can get really expensive and it can potentially trigger a lot of side effects. So instead, Dictionary.Exists tests the following:

  1. Are you comparing an object to a non-object? Automatic fail.
  2. Are you comparing two non-ojects? Return a = b.
  3. Are you comparing two objects? Return a Is b.

So r is not the same as r.Value, since one is an object and the other is a non-object. And if you make a copy of r, like with r.Offset(0, 0), those are not the same either since they still point to two different objects, even if the objects have identical contents.

This, on the other hand, will work, since you will make r into the same object as d.Keys(0):

Dim d As Scripting.Dictionary
Dim r As Range
Set r = [a1]
Set d = New Dictionary
d.Add r, 0
Set r = d.Keys(0)
Debug.Print d.Exists(r)


Related Topics



Leave a reply



Submit