Подтвердить что ты не робот

Как получить только подмножество упорядоченного хэша в Ruby 1.9?

Возьмем этот пример:

d = {"a" => 1, "b" => 2, "c" => 3, "d" => 4}

Поскольку хеши теперь упорядочены, мне может потребоваться получить данные от a до b или от c до d. Проблема в том, что я не могу выполнить d[0..1] или d[2..3].

Однако я мог:

irb > d.to_a[0..1]
=> [["a", 1], ["b", 2]] 

... но это кажется беспорядочным, и я не хочу использовать свой хэш для такой операции.

Есть ли более чистые решения для этого?

# Holy Grail
irb > d[0..1]
=> {"a" => 1, "b" => 2}

Я вижу, как программировать такой метод, но может быть что-то уже сделанное, что я мог бы использовать...?

4b9b3361

Ответ 1

Ну, вы могли бы сделать:

> a = {"a" => 1, "b" => 2, "c" => 3, "d" => 4}
> a.slice(*a.keys[0..1])
=> {"a" => 1, "b" => 1}

По крайней мере, хэш не отбрасывается, но, по-моему, он по-прежнему не очень изящный.

Ответ 2

Если вы хотите сделать сравнения на ключе, чтобы выбрать подмножество, вы можете использовать Hash#select, он также работает в 1.8.7 но вместо этого возвращает массив массивов (в соответствии с вашим примером).

d.select {|k, v| k < 'c' } # => {"a"=>1, "b"=>2}
d.select {|k, v| k < 'c' } # 1.8.7 => [["a", 1], ["b", 2]]

Вы также можете использовать расширение Hash для ActiveSupports, которое добавляет метод slice к Hash, который также может работать, если вы уже знаете ключи, которые вы хотите.

require 'active_support/core_ext/hash/slice'
d.slice('a', 'b') # => {"a"=>1, "b"=>2}

Ответ 3

Возможно, есть лучший способ сделать это, но это идея:

class Hash
    def slice_by_index(a, b = nil)  
        k = if a.is_a?(Range)
            keys[a]
        elsif b.nil?
            [keys[a]]
        else
            keys[a,b]
        end
        k.inject({}){|h, k| h[k] = self[k] ; h }
    end
end

h = {"a" => 1, "b" => 2, "c" => 3, "d" => 4}
p h.slice_by_index(1..3) #range
p h.slice_by_index(2) #single element
p h.slice_by_index(0,3) #start, lenght