在 Ruby 中将数组转换为索引哈希 [英] Convert an array into an index hash in Ruby

查看:53
本文介绍了在 Ruby 中将数组转换为索引哈希的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个数组,我想创建一个散列,这样我就可以快速询问数组中有 X 吗?".

I have an array, and I want to make a hash so I can quickly ask "is X in the array?".

在 perl 中,有一种简单(且快速)的方法可以做到这一点:

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,
}

我在 Ruby 中想到的最好的是:

The best I've come up with in Ruby is:

array = [1, 2, 3]
hash = Hash[array.map {|x| [x, nil]}]

给出:

{1=>nil, 2=>nil, 3=>nil}

有更好的 Ruby 方法吗?

Is there a better Ruby way?

不,Array.include?不是个好主意.它.它在 O(n) 而不是 O(1) 中执行查询.为简洁起见,我的示例数组包含三个元素;假设实际的有一百万个元素.让我们做一些基准测试:

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

产生:

                     user     system      total        real
Array.include?  46.190000   0.160000  46.350000 ( 46.593477)
Hash.include?    0.000000   0.000000   0.000000 (  0.000523)

推荐答案

如果你需要的只是成员资格,请考虑使用 Set:

If all you need the hash for is membership, consider using a Set:

Set 实现了一个无序值的集合,没有重复.这是 Array 直观互操作的混合体设施和哈希的快速查找.

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 易于与 Enumerable 对象(实现每个).大多数初始化方法和二元运算符都接受除了集合和数组之外的通用 Enumerable 对象.一个Enumerable 对象可以转换为 Set 使用to_set 方法.

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 the to_set method.

Set 使用Hash作为存储,所以一定要注意以下几点:

Set uses Hash as storage, so you must note the following points:

  • 元素的相等性是根据Object#eql?Object#hash确定的.
  • Set 假设每个元素的身份在存储时不会改变.修改集合的元素会将集合渲染为不可靠的状态.
  • 当要存储字符串时,除非原始字符串已被冻结,否则将存储该字符串的冻结副本.

比较运算符 <><=>= 实现为{proper_,}{subset?,superset?} 方法的简写.然而<=> 运算符被有意排除,因为不是每一对集是可比的.(例如,{x,y} 与 {x,z})

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)

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

[...]

创建一个包含给定可枚举元素的新集合对象.

Creates a new set containing the elements of the given enumerable object.

如果给定了一个块,则 enum 的元素由给定块.

If a block is given, the elements of enum are preprocessed by the given block.

这篇关于在 Ruby 中将数组转换为索引哈希的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆