class Hashery::Dictionary

The Dictionary class is a Hash that preserves order. So it has some array-like extensions also. By defualt a Dictionary object preserves insertion order, but any order can be specified including alphabetical key order.

Using a Dictionary is almost the same as using a Hash.

# You can do simply
hsh = Dictionary.new
hsh['z'] = 1
hsh['a'] = 2
hsh['c'] = 3
p hsh.keys     #=> ['z','a','c']

# or using Dictionary[] method
hsh = Dictionary['z', 1, 'a', 2, 'c', 3]
p hsh.keys     #=> ['z','a','c']

# but this don't preserve order
hsh = Dictionary['z'=>1, 'a'=>2, 'c'=>3]
p hsh.keys     #=> ['a','c','z']

# Dictionary has useful extensions: push, pop and unshift
p hsh.push('to_end', 15)       #=> true, key added
p hsh.push('to_end', 30)       #=> false, already - nothing happen
p hsh.unshift('to_begin', 50)  #=> true, key added
p hsh.unshift('to_begin', 60)  #=> false, already - nothing happen
p hsh.keys                     #=> ["to_begin", "a", "c", "z", "to_end"]
p hsh.pop                      #=> ["to_end", 15], if nothing remains, return nil
p hsh.keys                     #=> ["to_begin", "a", "c", "z"]
p hsh.shift                    #=> ["to_begin", 30], if nothing remains, return nil

Notes

Acknowledgments

Dictionary is a port of OrderHash 2.0 Copyright © 2005 Jan Molic.

People who have contributed to this class since then include:

OrderedHash is public domain.

Public Class Methods

[](*args) click to toggle source

Create a new Dictionary storing argument pairs as an initial mapping.

TODO: Is this needed? Doesn't the super class do this?

Returns Dictionary instance.

# File lib/hashery/dictionary.rb, line 67
def [](*args)
  hsh = new
  if Hash === args[0]
    hsh.replace(args[0])
  elsif (args.size % 2) != 0
    raise ArgumentError, "odd number of elements for Hash"
  else
    while !args.empty?
      hsh[args.shift] = args.shift
    end
  end
  hsh
end
alpha(*args, &block)

DEPRECATED: Use alphabetic instead.

Alias for: alphabetic
alphabetic(*args, &block) click to toggle source

Alternate to new which creates a dictionary sorted by the key as a string.

d = Dictionary.alphabetic
d["z"] = 1
d["y"] = 2
d["x"] = 3
d  #=> {"x"=>3,"y"=>2,"z"=>2}

This is equivalent to:

Dictionary.new.order_by { |key,value| key.to_s }
# File lib/hashery/dictionary.rb, line 103
def alphabetic(*args, &block)
  new(*args, &block).order_by { |key,value| key.to_s }
end
Also aliased as: alpha
auto(*args) click to toggle source

Alternate to new which auto-creates sub-dictionaries as needed.

Examples

d = Dictionary.auto
d["a"]["b"]["c"] = "abc"  #=> { "a"=>{"b"=>{"c"=>"abc"}}}
# File lib/hashery/dictionary.rb, line 118
def auto(*args)
  #AutoDictionary.new(*args)
  leet = lambda { |hsh, key| hsh[key] = new(&leet) }
  new(*args, &leet)
end
new(*args, &blk) click to toggle source

New Dictiionary.

# File lib/hashery/dictionary.rb, line 128
def initialize(*args, &blk)
  @order = []
  @order_by = nil
  if blk
    dict = self                                  # This ensures automatic key entry effect the
    oblk = lambda{ |hsh, key| blk[dict,key] }    # dictionary rather then just the interal hash.
    @hash = Hash.new(*args, &oblk)
  else
    @hash = Hash.new(*args)
  end
end
new_by(*args, &blk) click to toggle source

Like new but the block sets the order instead of the default.

Dictionary.new_by{ |k,v| k }
# File lib/hashery/dictionary.rb, line 86
def new_by(*args, &blk)
  new(*args).order_by(&blk)
end

Public Instance Methods

<<(kv) click to toggle source

Same as push.

# File lib/hashery/dictionary.rb, line 441
def <<(kv)
  push(*kv)
end
==(hsh2) click to toggle source

Is the dictionary instance equivalent to another?

# File lib/hashery/dictionary.rb, line 232
def ==(hsh2)
  if hsh2.is_a?( Dictionary )
    @order == hsh2.order &&
    @hash  == hsh2.instance_variable_get("@hash")
  else
    false
  end
end
[](key) click to toggle source

Lookup entry with key.

# File lib/hashery/dictionary.rb, line 244
def [] key
  @hash[ key ]
end
[]=(k, i=nil, v=nil) click to toggle source

Store operator.

h[key] = value

Or with additional index.

h[key,index] = value
# File lib/hashery/dictionary.rb, line 264
def []=(k, i=nil, v=nil)
  if v
    insert(i,k,v)
  else
    store(k,i)
  end
end
clear() click to toggle source

Clear dictionary of all entries.

# File lib/hashery/dictionary.rb, line 299
def clear
  @order = []
  @hash.clear
end
delete(key) click to toggle source

Delete the entry with given key.

# File lib/hashery/dictionary.rb, line 307
def delete(key)
  @order.delete(key)
  @hash.delete(key)
end
delete_if() { |k,hash| ... } click to toggle source

Delete entry if it fits conditional block.

# File lib/hashery/dictionary.rb, line 341
def delete_if
  order.clone.each { |k| delete k if yield(k,@hash[k]) }
  self
end
dup() click to toggle source

Duplicate dictionary.

Returns [Dictionary].

# File lib/hashery/dictionary.rb, line 482
def dup
  a = []
  each{ |k,v| a << k; a << v }
  self.class[*a]
end
each() { |k,hash| ... } click to toggle source

Iterate over each key-value pair.

# File lib/hashery/dictionary.rb, line 331
def each
  order.each { |k| yield( k,@hash[k] ) }
  self
end
Also aliased as: each_pair
each_key() { |k| ... } click to toggle source

Iterate over each key.

# File lib/hashery/dictionary.rb, line 315
def each_key
  order.each { |k| yield( k ) }
  self
end
each_pair()
Alias for: each
each_value() { |hash| ... } click to toggle source

Iterate over each value.

# File lib/hashery/dictionary.rb, line 323
def each_value
  order.each { |k| yield( @hash[k] ) }
  self
end
empty?() click to toggle source

Is the dictionary empty?

Returns `true` or `false`.

# File lib/hashery/dictionary.rb, line 570
def empty?
  @hash.empty?
end
fetch(key, *a, &b) click to toggle source

Featch entry given key.

# File lib/hashery/dictionary.rb, line 251
def fetch(key, *a, &b)
  @hash.fetch(key, *a, &b)
end
first(x=nil) click to toggle source

Get/set initial entry value.

# File lib/hashery/dictionary.rb, line 543
def first(x=nil)
  return @hash[order.first] unless x
  order.first(x).collect { |k| @hash[k] }
end
has_key?(key) click to toggle source

Does the dictionary have a given key.

Returns `true` or `false`.

# File lib/hashery/dictionary.rb, line 579
def has_key?(key)
  @hash.has_key?(key)
end
insert(index, key, value) click to toggle source

Insert entry into dictionary at specific index position.

index - [Integer] Position of order placement. key - [Object] Key to associate with value. value - [Object] Value to associate with key.

Returns `value` stored.

# File lib/hashery/dictionary.rb, line 281
def insert(index, key, value)
  @order.insert(index, key)
  @hash.store(key, value)
end
inspect() click to toggle source

Inspection string for Dictionary.

Returns [String].

# File lib/hashery/dictionary.rb, line 471
def inspect
  ary = []
  each {|k,v| ary << k.inspect + "=>" + v.inspect}
  '{' + ary.join(", ") + '}'
end
invert() click to toggle source

Invert the dictionary.

Returns [Dictionary] New dictionary that is inverse of the original.

# File lib/hashery/dictionary.rb, line 371
def invert
  hsh2 = self.class.new
  order.each { |k| hsh2[@hash[k]] = k }
  hsh2
end
key?(key) click to toggle source

Does the dictionary have a given key.

Returns `true` or `false`.

# File lib/hashery/dictionary.rb, line 588
def key?(key)
  @hash.key?(key)
end
keys() click to toggle source

List of all dictionary keys.

Returns [Array].

# File lib/hashery/dictionary.rb, line 362
def keys
  order
end
last(x=nil) click to toggle source

Get/set last entry value.

# File lib/hashery/dictionary.rb, line 551
def last(x=nil)
  return @hash[order.last] unless x
  order.last(x).collect { |k| @hash[k] }
end
length() click to toggle source

Number of items in the dictionary.

# File lib/hashery/dictionary.rb, line 559
def length
  @order.length
end
Also aliased as: size
merge(hsh2) click to toggle source

Merge other hash creating new dictionary.

Returns [Dictionary].

# File lib/hashery/dictionary.rb, line 506
def merge(hsh2)
  self.dup.update(hsh2)
end
merge!( hsh2 )
Alias for: update
order() click to toggle source

Order of keys.

Returns [Array].

# File lib/hashery/dictionary.rb, line 145
def order
  reorder if @order_by
  @order
end
order_by( &block ) click to toggle source

Keep dictionary sorted by a specific sort order.

block - Ordering procedure.

Returns self.

# File lib/hashery/dictionary.rb, line 157
def order_by( &block )
  @order_by = block
  order
  self
end
order_by_key() { |k| ... } click to toggle source

Keep dictionary sorted by key.

d = Dictionary.new.order_by_key
d["z"] = 1
d["y"] = 2
d["x"] = 3
d  #=> {"x"=>3,"y"=>2,"z"=>2}

This is equivalent to:

Dictionary.new.order_by { |key,value| key }

The initializer Dictionary#alpha also provides this.

Returns self.

# File lib/hashery/dictionary.rb, line 180
def order_by_key
  if block_given?
    @order_by = Proc.new{ |k,v| yield(k) }
  else
    @order_by = Proc.new{ |k,v| k }
  end
  order
  self
end
order_by_value() { |v| ... } click to toggle source

Keep dictionary sorted by value.

d = Dictionary.new.order_by_value
d["z"] = 1
d["y"] = 2
d["x"] = 3
d  #=> {"x"=>3,"y"=>2,"z"=>2}

This is equivalent to:

Dictionary.new.order_by { |key,value| value }
# File lib/hashery/dictionary.rb, line 203
def order_by_value
  if block_given?
    @order_by = Proc.new{ |k,v| yield(v) }
  else
    @order_by = Proc.new{ |k,v| v }
  end
  order
  self
end
pop() click to toggle source

Pop entry off the bottom of dictionary.

# File lib/hashery/dictionary.rb, line 461
def pop
  key = order.last
  key ? [key,delete(key)] : nil
end
push(k,v) click to toggle source

Push entry on to bottom of the dictionary.

# File lib/hashery/dictionary.rb, line 448
def push(k,v)
  unless @hash.include?( k )
    @order.push( k )
    @hash.store( k,v )
    true
  else
    false
  end
end
reject(&block) click to toggle source

Reject entries based on give condition block and return new dictionary.

Returns [Dictionary].

# File lib/hashery/dictionary.rb, line 383
def reject(&block)
  self.dup.delete_if(&block)
end
reject!( &block ) click to toggle source

Reject entries based on give condition block.

Returns [Hash] of rejected entries.

FIXME: This looks like it is implemented wrong!!!

# File lib/hashery/dictionary.rb, line 394
def reject!( &block )
  hsh2 = reject(&block)
  self == hsh2 ? nil : hsh2
end
reorder() click to toggle source

Re-apply the sorting procedure.

# File lib/hashery/dictionary.rb, line 216
def reorder
  if @order_by
    assoc = @order.collect{ |k| [k,@hash[k]] }.sort_by(&@order_by)
    @order = assoc.collect{ |k,v| k }
  end
  @order
end
replace(hsh2) click to toggle source

Replace dictionary entries with new table.

# File lib/hashery/dictionary.rb, line 402
def replace(hsh2)
  case hsh2
  when Dictionary
    @order = hsh2.order
    @hash  = hsh2.to_h
  when Hash
    @hash  = hsh2
    @order = @hash.keys
  else
    @hash  = hsh2.to_h
    @order = @hash.keys
  end
  reorder
end
reverse() click to toggle source

Reverse the order of duplicte dictionary.

Returns [Dictionary].

# File lib/hashery/dictionary.rb, line 536
def reverse
  dup.reverse!
end
reverse!() click to toggle source

Reverse the order of the dictionary.

Returns self.

# File lib/hashery/dictionary.rb, line 526
def reverse!
  @order.reverse!
  self
end
select() { |k,v| ... } click to toggle source

Select items from dictiornary.

Returns [Array] of two-element arrays.

# File lib/hashery/dictionary.rb, line 515
def select
  ary = []
  each { |k,v| ary << [k,v] if yield k,v }
  ary
end
shift() click to toggle source

Remove entry from the to top of dictionary.

Calls superclass method
# File lib/hashery/dictionary.rb, line 420
def shift
  key = order.first
  key ? [key,delete(key)] : super
end
size()
Alias for: length
store(key, value) click to toggle source

Add entry into dictionary.

Returns `value`.

# File lib/hashery/dictionary.rb, line 291
def store(key, value)
  @order.push(key) unless @hash.has_key?(key)
  @hash.store(key, value)
end
to_a() click to toggle source

Convert to array.

Returns [Array] of two-element arrays.

# File lib/hashery/dictionary.rb, line 597
def to_a
  ary = []
  each { |k,v| ary << [k,v] }
  ary
end
to_h() click to toggle source

Get a duplicate of the underlying hash table.

Returns [Hash].

# File lib/hashery/dictionary.rb, line 626
def to_h
  @hash.dup
end
to_hash() click to toggle source

Get a duplicate of the underlying hash table.

Returns [Hash].

# File lib/hashery/dictionary.rb, line 617
def to_hash
  @hash.dup
end
to_s() click to toggle source

Convert to array then to string.

Returns [String].

# File lib/hashery/dictionary.rb, line 608
def to_s
  self.to_a.to_s
end
unshift( k,v ) click to toggle source

Push entry on to the top of dictionary.

# File lib/hashery/dictionary.rb, line 428
def unshift( k,v )
  unless @hash.include?( k )
    @order.unshift( k )
    @hash.store( k,v )
    true
  else
    false
  end
end
update( hsh2 ) click to toggle source

Update dictionary with other hash.

Returns self.

# File lib/hashery/dictionary.rb, line 493
def update( hsh2 )
  hsh2.each { |k,v| self[k] = v }
  reorder
  self
end
Also aliased as: merge!
values() click to toggle source

List of all dictionary values.

Returns [Array].

# File lib/hashery/dictionary.rb, line 351
def values
  ary = []
  order.each { |k| ary.push @hash[k] }
  ary
end

Protected Instance Methods

hash_table() click to toggle source

Underlying hash table.

# File lib/hashery/dictionary.rb, line 635
def hash_table
  @hash
end