I have an array, and I want to make a hash so I can quickly ask "is X in the array?".
In perl, there is an easy (and fast) way to do this:
my @array = qw( 1 2 3 ); my %hash; @hash{@array} = undef;
This generates a hash that looks like:
{ 1 => undef, 2 => undef, 3 => undef, }
The best I've come up with in Ruby is:
array = [1, 2, 3] hash = Hash[array.map {|x| [x, nil]}]
which gives:
{1=>nil, 2=>nil, 3=>nil}
Is there a better Ruby way?
No, Array.include? is not a good idea. Its slow. It does a query in O(n) instead of O(1). My example array had three elements for brevity; assume the actual one has a million elements. Let's do a little benchmarking:
#!/usr/bin/ruby -w require 'benchmark' array = (1..1_000_000).to_a hash = Hash[array.map {|x| [x, nil]}] Benchmark.bm(15) do |x| x.report("Array.include?") { 1000.times { array.include?(500_000) } } x.report("Hash.include?") { 1000.times { hash.include?(500_000) } } end
Produces:
user system total real Array.include? 46.190000 0.160000 46.350000 ( 46.593477) Hash.include? 0.000000 0.000000 0.000000 ( 0.000523)
The to_h method is defined in the array class. It works to convert an array to a hash in the form of key-value pairs. The method converts each nested array into key-value pairs. The method also accepts a block.
In Ruby you can create a Hash by assigning a key to a value with => , separate these key/value pairs with commas, and enclose the whole thing with curly braces.
Ruby | Array to_h() function Array#to_h() : to_h() is a Array class method which returns the result of interpreting ary as an array of [key, value] pairs. Syntax: Array.to_h() Parameter: Array. Return: the result of interpreting ary as an array of [key, value] pairs.
A Hash is a collection of key-value pairs. It is similar to an Array , except that indexing is done via arbitrary keys of any object type, not an integer index.
If all you need the hash for is membership, consider using a Set
:
Set
Set implements a collection of unordered values with no duplicates. This is a hybrid of Array's intuitive inter-operation facilities and Hash's fast lookup.
Set is easy to use with Enumerable objects (implementing
each
). Most of the initializer methods and binary operators accept generic Enumerable objects besides sets and arrays. An Enumerable object can be converted to Set using theto_set
method.Set uses Hash as storage, so you must note the following points:
- Equality of elements is determined according to
Object#eql?
andObject#hash
.- Set assumes that the identity of each element does not change while it is stored. Modifying an element of a set will render the set to an unreliable state.
- When a string is to be stored, a frozen copy of the string is stored instead unless the original string is already frozen.
Comparison
The comparison operators
<
,>
,<=
and>=
are implemented as shorthand for the {proper_,}{subset?,superset?} methods. However, the<=>
operator is intentionally left out because not every pair of sets is comparable. ({x,y} vs. {x,z} for example)Example
require 'set' s1 = Set.new [1, 2] # -> #<Set: {1, 2}> s2 = [1, 2].to_set # -> #<Set: {1, 2}> s1 == s2 # -> true s1.add("foo") # -> #<Set: {1, 2, "foo"}> s1.merge([2, 6]) # -> #<Set: {1, 2, "foo", 6}> s1.subset? s2 # -> false s2.subset? s1 # -> true
[...]
Public Class Methods
new(enum = nil)
Creates a new set containing the elements of the given enumerable object.
If a block is given, the elements of enum are preprocessed by the given block.
try this one:
a=[1,2,3] Hash[a.zip]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With