Indexing `OrderedDict`s by index instead of key

One can access values of OrderedDicts by their index by exposing the internal vals field, like so:

julia> od = sort(Dict('a'=>'A', 'b'=>'B'))
OrderedCollections.OrderedDict{Char, Char} with 2 entries:
  'a' => 'A'
  'b' => 'B'

julia> od.vals[2]
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)

But this doesn’t feel like the “front-end” way of doing this — I always find myself wanting to write values(od) and being surprised when the ValueIterator object it returns doesn’t support indexing.

Should I submit a PR to OrderedCollections.jl and implement getindex(::ValueIterator{<:OrderedDict}, …) so that values(od)[2] works?

I only hesitate because values does’t seem to return getindex-able objects normally. I’m not sure if that’s by design.

I’m over-thinking it. Here is a PR, I’ll see what the maintainers think.

A generic approach would be to implement a collect which allows for certain index ranges, like:

collect(values(d),startindex,lastindex)

which doesn’t allocate the complete array like in:

collect(values(d))[startindex:lastindex]

Using internal d.vals is problematic as, e.g. it does work for OrderedDict only by fortune, see:

julia> d=Dict("a" => "12345", "b" => "23345", "c" => "654645");

julia> d.vals
16-element Vector{String}:
 #undef
 #undef
 #undef
    "654645"
 #undef
 #undef
 #undef
 #undef
    "23345"
 #undef
 #undef
 #undef
 #undef
    "12345"
 #undef
 #undef
1 Like

You’re quite right. I was careful to only add methods for OrderedDicts, not normal Dicts:

Base.getindex(h::Base.KeySet{K,<:OrderedDict{K}}, index) where K = h.dict.keys[index]
Base.getindex(h::Base.ValueIterator{<:OrderedDict}, index) = h.dict.vals[index]

Assuming the internal layout of OrderedDicts always works this way…

Perhaps there’s another dictionary-like data structure which is intended to be getindexed by key and/or linear index, without temporary allocation?