Class: Dictionary

Inherits:
Object show all
Includes:
Enumerable
Defined in:
lib/more/facets/dictionary.rb

Overview

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.

Usage

Just require this file and use Dictionary instead of 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

Usage Notes

  • You can use #order_by to set internal sort order.

  • #<< takes a two element [k,v] array and inserts.

  • Use ::auto which creates Dictionay sub-entries as needed.

  • And ::alpha which creates a new Dictionary sorted by key.

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Enumerable

#**, #accumulate, cart, #cartesian_product, cartesian_product, #cluster_by, #collect_if, #collect_with_index, combinations, #combos, #commonality, #compact_collect, #count, #divide, #each_by, #each_combination, #each_combo, #each_permutation, #eachn, #elementwise, #entropy, #every, #every!, #filter_collect, #frequency, #group_by, #ideal_entropy, #inject!, #injecting, #map_send, #mash, #mode, #modulate, #none?, #nonuniq, #occur, #one?, #permutation, #permutation_number, #probability, #split, #sum, #threaded_map, #threaded_map_send, #to_elem, #uniq_by

Constructor Details

#initialize(*args, &blk) ⇒ Dictionary

New Dictiionary.



139
140
141
142
143
144
145
146
147
148
149
# File 'lib/more/facets/dictionary.rb', line 139

def initialize(*args, &blk)
  @order = []
  @order_by = nil
  if blk
    dict = self                                  # This ensure autmatic 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

Class Method Details

.[](*args) ⇒ Object

– TODO is this needed? Doesn’t the super class do this? ++



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/more/facets/dictionary.rb', line 89

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) ⇒ Object

Alternate to #new which creates a dictionary sorted by key.

d = Dictionary.alpha
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 }


121
122
123
# File 'lib/more/facets/dictionary.rb', line 121

def alpha(*args, &block)
  new(*args, &block).order_by_key
end

.auto(*args) ⇒ Object

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

d = Dictionary.auto
d["a"]["b"]["c"] = "abc"  #=> { "a"=>{"b"=>{"c"=>"abc"}}}


130
131
132
133
134
# File 'lib/more/facets/dictionary.rb', line 130

def auto(*args)
  #AutoDictionary.new(*args)
  leet = lambda { |hsh, key| hsh[key] = new(&leet) }
  new(*args, &leet)
end

.new_by(*args, &blk) ⇒ Object

Like #new but the block sets the order.



105
106
107
# File 'lib/more/facets/dictionary.rb', line 105

def new_by(*args, &blk)
  new(*args).order_by(&blk)
end

Instance Method Details

#<<(kv) ⇒ Object



336
337
338
# File 'lib/more/facets/dictionary.rb', line 336

def <<(kv)
  push *kv
end

#==(hsh2) ⇒ Object

def ==( hsh2 )

return false if @order != hsh2.order
super hsh2

end



217
218
219
220
221
222
223
224
# File 'lib/more/facets/dictionary.rb', line 217

def ==(hsh2)
  if hsh2.is_a?( Dictionary )
    @order == hsh2.order &&
    @hash  == hsh2.instance_variable_get("@hash")
  else
    false
  end
end

#[](k) ⇒ Object



226
227
228
# File 'lib/more/facets/dictionary.rb', line 226

def [] k
  @hash[ k ]
end

#[]=(k, i = nil, v = nil) ⇒ Object

Store operator.

h[key] = value

Or with additional index.

h[key,index] = value


242
243
244
245
246
247
248
# File 'lib/more/facets/dictionary.rb', line 242

def []=(k, i=nil, v=nil)
  if v
    insert(i,k,v)
  else
    store(k,i)
  end
end

#clearObject



260
261
262
263
# File 'lib/more/facets/dictionary.rb', line 260

def clear
  @order = []
  @hash.clear
end

#delete(key) ⇒ Object



265
266
267
268
# File 'lib/more/facets/dictionary.rb', line 265

def delete( key )
  @order.delete( key )
  @hash.delete( key )
end

#delete_ifObject



286
287
288
289
# File 'lib/more/facets/dictionary.rb', line 286

def delete_if
  order.clone.each { |k| delete k if yield(k,@hash[k]) }
  self
end

#dupObject



361
362
363
364
365
# File 'lib/more/facets/dictionary.rb', line 361

def dup
  a = []
  each{ |k,v| a << k; a << v }
  self.class[*a]
end

#eachObject Also known as: each_pair



280
281
282
283
# File 'lib/more/facets/dictionary.rb', line 280

def each
  order.each { |k| yield( k,@hash[k] ) }
  self
end

#each_keyObject



270
271
272
273
# File 'lib/more/facets/dictionary.rb', line 270

def each_key
  order.each { |k| yield( k ) }
  self
end

#each_valueObject



275
276
277
278
# File 'lib/more/facets/dictionary.rb', line 275

def each_value
  order.each { |k| yield( @hash[k] ) }
  self
end

#empty?Boolean

Returns:

  • (Boolean)


406
407
408
# File 'lib/more/facets/dictionary.rb', line 406

def empty?
  @hash.empty?
end

#fetch(k, *a, &b) ⇒ Object



230
231
232
# File 'lib/more/facets/dictionary.rb', line 230

def fetch(k, *a, &b)
  @hash.fetch(k, *a, &b)
end

#firstObject



393
394
395
# File 'lib/more/facets/dictionary.rb', line 393

def first
  @hash[order.first]
end

#has_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


410
411
412
# File 'lib/more/facets/dictionary.rb', line 410

def has_key?(key)
  @hash.has_key?(key)
end

#insert(i, k, v) ⇒ Object



250
251
252
253
# File 'lib/more/facets/dictionary.rb', line 250

def insert( i,k,v )
  @order.insert( i,k )
  @hash.store( k,v )
end

#inspectObject



355
356
357
358
359
# File 'lib/more/facets/dictionary.rb', line 355

def inspect
  ary = []
  each {|k,v| ary << k.inspect + "=>" + v.inspect}
  '{' + ary.join(", ") + '}'
end

#invertObject



301
302
303
304
305
# File 'lib/more/facets/dictionary.rb', line 301

def invert
  hsh2 = self.class.new
  order.each { |k| hsh2[@hash[k]] = k }
  hsh2
end

#key?(key) ⇒ Boolean

Returns:

  • (Boolean)


414
415
416
# File 'lib/more/facets/dictionary.rb', line 414

def key?(key)
  @hash.key?(key)
end

#keysObject



297
298
299
# File 'lib/more/facets/dictionary.rb', line 297

def keys
  order
end

#lastObject



397
398
399
# File 'lib/more/facets/dictionary.rb', line 397

def last
  @hash[order.last]
end

#lengthObject Also known as: size



401
402
403
# File 'lib/more/facets/dictionary.rb', line 401

def length
  @order.length
end

#merge(hsh2) ⇒ Object



374
375
376
# File 'lib/more/facets/dictionary.rb', line 374

def merge( hsh2 )
  self.dup.update(hsh2)
end

#orderObject



151
152
153
154
# File 'lib/more/facets/dictionary.rb', line 151

def order
  reorder if @order_by
  @order
end

#order_by(&block) ⇒ Object

Keep dictionary sorted by a specific sort order.



158
159
160
161
162
# File 'lib/more/facets/dictionary.rb', line 158

def order_by( &block )
  @order_by = block
  order
  self
end

#order_by_keyObject

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.



178
179
180
181
182
# File 'lib/more/facets/dictionary.rb', line 178

def order_by_key
  @order_by = lambda { |k,v| k }
  order
  self
end

#order_by_valueObject

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 }


196
197
198
199
200
# File 'lib/more/facets/dictionary.rb', line 196

def order_by_value
  @order_by = lambda { |k,v| v }
  order
  self
end

#popObject



350
351
352
353
# File 'lib/more/facets/dictionary.rb', line 350

def pop
  key = order.last
  key ? [key,delete(key)] : nil
end

#push(k, v) ⇒ Object



340
341
342
343
344
345
346
347
348
# File 'lib/more/facets/dictionary.rb', line 340

def push( k,v )
  unless @hash.include?( k )
    @order.push( k )
    @hash.store( k,v )
    true
  else
    false
  end
end

#reject(&block) ⇒ Object



307
308
309
# File 'lib/more/facets/dictionary.rb', line 307

def reject( &block )
  self.dup.delete_if &block
end

#reject!(&block) ⇒ Object



311
312
313
314
# File 'lib/more/facets/dictionary.rb', line 311

def reject!( &block )
  hsh2 = reject &block
  self == hsh2 ? nil : hsh2
end

#reorderObject



204
205
206
207
208
209
210
# File 'lib/more/facets/dictionary.rb', line 204

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) ⇒ Object



316
317
318
319
# File 'lib/more/facets/dictionary.rb', line 316

def replace( hsh2 )
  @order = hsh2.order
  @hash = hsh2.hash
end

#reverseObject



389
390
391
# File 'lib/more/facets/dictionary.rb', line 389

def reverse
  dup.reverse!
end

#reverse!Object



384
385
386
387
# File 'lib/more/facets/dictionary.rb', line 384

def reverse!
  @order.reverse!
  self
end

#selectObject



378
379
380
381
382
# File 'lib/more/facets/dictionary.rb', line 378

def select
  ary = []
  each { |k,v| ary << [k,v] if yield k,v }
  ary
end

#shiftObject



321
322
323
324
# File 'lib/more/facets/dictionary.rb', line 321

def shift
  key = order.first
  key ? [key,delete(key)] : super
end

#store(a, b) ⇒ Object



255
256
257
258
# File 'lib/more/facets/dictionary.rb', line 255

def store( a,b )
  @order.push( a ) unless @hash.has_key?( a )
  @hash.store( a,b )
end

#to_aObject



418
419
420
421
422
# File 'lib/more/facets/dictionary.rb', line 418

def to_a
  ary = []
  each { |k,v| ary << [k,v] }
  ary
end

#to_hObject



432
433
434
# File 'lib/more/facets/dictionary.rb', line 432

def to_h
  @hash.dup
end

#to_hashObject



428
429
430
# File 'lib/more/facets/dictionary.rb', line 428

def to_hash
  @hash.dup
end

#to_sObject



424
425
426
# File 'lib/more/facets/dictionary.rb', line 424

def to_s
  self.to_a.to_s
end

#unshift(k, v) ⇒ Object



326
327
328
329
330
331
332
333
334
# File 'lib/more/facets/dictionary.rb', line 326

def unshift( k,v )
  unless @hash.include?( k )
    @order.unshift( k )
    @hash.store( k,v )
    true
  else
    false
  end
end

#update(hsh2) ⇒ Object Also known as: merge!



367
368
369
370
371
# File 'lib/more/facets/dictionary.rb', line 367

def update( hsh2 )
  hsh2.each { |k,v| self[k] = v }
  reorder
  self
end

#valuesObject



291
292
293
294
295
# File 'lib/more/facets/dictionary.rb', line 291

def values
  ary = []
  order.each { |k| ary.push @hash[k] }
  ary
end