开发者

How to get only a subset of an ordered hash in Ruby 1.9?

开发者 https://www.devze.com 2023-04-11 10:15 出处:网络
Let\'s take this example: d = {\"a\" => 1, \"b开发者_StackOverflow社区\" => 2, \"c\" => 3, \"d\" => 4}

Let's take this example:

d = {"a" => 1, "b开发者_StackOverflow社区" => 2, "c" => 3, "d" => 4}

Since hashes are now ordered, I might want to get data from a to b or from c to d. The problem is that I can't do d[0..1] or d[2..3].

I could however do:

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

... but this feels messy and I don't want to cast my hash for an operation like this.

Is there a cleaner solution to handle this?

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

I can see how to program myself such a method, but there might be something native already done that I could use...?


Well you could do :

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

At least the hash is not cast, but it's still not very elegant in my opinion.


If you want to make comparisons on the key to select the subset, you can use Hash#select, it also works in 1.8.7 but returns an array of arrays instead (as per your example).

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

You can also use ActiveSupport’s Hash extension that adds a slice method to Hash that can also work, provided you already know the keys you want.

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


Probably there's a better way to do it but this is an idea:

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
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号