класс Hash
Словарь — это подобная словарю коллекция уникальных ключей и их значений. Также называемые ассоциативными массивами, они похожи на массивы, но где массив использует целые числа в качестве индексов, словарь позволяет использовать любой тип объекта.
Словари перечисляют свои значения в том порядке, в котором соответствующие ключи были вставлены.
Словарь можно легко создать, используя его неявную форму:
grades = { "Jane Doe" => 10, "Jim Doe" => 6 }
Словари позволяют использовать альтернативный синтаксис для ключей, которые являются символами. Вместо
options = { :font_size => 10, :font_family => "Arial" }
Вы можете написать это как:
options = { font_size: 10, font_family: "Arial" }
Каждый именованный ключ — это символ, к которому вы можете получить доступ в словаре:
options[:font_size] # => 10
Словарь также можно создать с помощью своего метода ::new:
grades = Hash.new grades["Dorothy Doe"] = 9
У словаря есть значение по умолчанию, которое возвращается при обращении к ключам, которые не существуют в словаре. Если значение по умолчанию не задано, используется nil. Вы можете установить значение по умолчанию, передав его в качестве аргумента методу Hash.new:
grades = Hash.new(0)
Или с помощью метода default=:
grades = {"Timmy Doe" => 8}
grades.default = 0
Для доступа к значению в словаре необходимо использовать его ключ:
puts grades["Jane Doe"] # => 0
Общие применения
Словари — это простой способ представления структур данных, таких как
books = {}
books[:matz] = "The Ruby Programming Language"
books[:black] = "The Well-Grounded Rubyist"
Словари также часто используются для именованных параметров в функциях. Обратите внимание, что ниже не используются скобки. Если словарь является последним аргументом в вызове метода, скобки не нужны, что создает действительно чистый интерфейс:
Person.create(name: "John Doe", age: 27) def self.create(params) @name = params[:name] @age = params[:age] end
Hash Ключи словаря
Два объекта ссылаются на один и тот же ключ словаря, когда их значение hash идентично, и два объекта eql? друг другу.
Пользовательский класс может использоваться в качестве ключа словаря, если методы hash и eql? переопределены для предоставления осмысленного поведения. По умолчанию отдельные экземпляры ссылаются на отдельные ключи словаря.
Типичная реализация hash основана на данных объекта, в то время как eql? обычно является псевдонимом переопределённого метода ==:
class Book
attr_reader :author, :title
def initialize(author, title)
@author = author
@title = title
end
def ==(other)
self.class === other and
other.author == @author and
other.title == @title
end
alias eql? ==
def hash
@author.hash ^ @title.hash # XOR
end
end
book1 = Book.new 'matz', 'Ruby in a Nutshell'
book2 = Book.new 'matz', 'Ruby in a Nutshell'
reviews = {}
reviews[book1] = 'Great reference!'
reviews[book2] = 'Nice and compact!'
reviews.length #=> 1
См. также Object#hash и Object#eql?
Публичные методы класса
static VALUE
rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
{
VALUE hash, tmp;
if (argc == 1) {
tmp = rb_hash_s_try_convert(Qnil, argv[0]);
if (!NIL_P(tmp)) {
hash = hash_alloc(klass);
if (RHASH_AR_TABLE_P(tmp)) {
ar_copy(hash, tmp);
}
else {
RHASH_ST_TABLE_SET(hash, st_copy(RHASH_ST_TABLE(tmp)));
}
return hash;
}
tmp = rb_check_array_type(argv[0]);
if (!NIL_P(tmp)) {
long i;
hash = hash_alloc(klass);
for (i = 0; i < RARRAY_LEN(tmp); ++i) {
VALUE e = RARRAY_AREF(tmp, i);
VALUE v = rb_check_array_type(e);
VALUE key, val = Qnil;
if (NIL_P(v)) {
rb_raise(rb_eArgError, "wrong element type %s at %ld (expected array)",
rb_builtin_class_name(e), i);
}
switch (RARRAY_LEN(v)) {
default:
rb_raise(rb_eArgError, "invalid number of elements (%ld for 1..2)",
RARRAY_LEN(v));
case 2:
val = RARRAY_AREF(v, 1);
case 1:
key = RARRAY_AREF(v, 0);
rb_hash_aset(hash, key, val);
}
}
return hash;
}
}
if (argc % 2 != 0) {
rb_raise(rb_eArgError, "odd number of arguments for Hash");
}
hash = hash_alloc(klass);
rb_hash_bulk_insert(argc, argv, hash);
hash_verify(hash);
return hash;
} Создает новый словарь, заполненный заданными объектами.
Аналогично литералу { key => value, ... }. В первой форме ключи и значения встречаются парами, поэтому должно быть чётное количество аргументов.
Во второй и третьей форме принимается единственный аргумент, который является либо массивом пар ключ-значение, либо объектом, преобразуемым в словарь.
Hash["a", 100, "b", 200] #=> {"a"=>100, "b"=>200}
Hash[ [ ["a", 100], ["b", 200] ] ] #=> {"a"=>100, "b"=>200}
Hash["a" => 100, "b" => 200] #=> {"a"=>100, "b"=>200}
static VALUE
rb_hash_initialize(int argc, VALUE *argv, VALUE hash)
{
VALUE ifnone;
rb_hash_modify(hash);
if (rb_block_given_p()) {
rb_check_arity(argc, 0, 0);
ifnone = rb_block_proc();
SET_PROC_DEFAULT(hash, ifnone);
}
else {
rb_check_arity(argc, 0, 1);
ifnone = argc == 0 ? Qnil : argv[0];
RHASH_SET_IFNONE(hash, ifnone);
}
return hash;
} Возвращает новый пустой словарь. Если к этому словарю впоследствии обращаются по ключу, который не соответствует записи в словаре, возвращаемое значение зависит от стиля new , используемого для создания словаря. В первой форме обращение возвращает nil. Если указан объект, этот единственный объект будет использоваться для всех значений по умолчанию. Если указан блок, он будет вызываться с объектом словаря и ключом и должен возвращать значение по умолчанию. Блок несет ответственность за сохранение значения в словаре, если это необходимо.
h = Hash.new("Go Fish")
h["a"] = 100
h["b"] = 200
h["a"] #=> 100
h["c"] #=> "Go Fish"
# The following alters the single default object
h["c"].upcase! #=> "GO FISH"
h["d"] #=> "GO FISH"
h.keys #=> ["a", "b"]
# While this creates a new default object each time
h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
h["c"] #=> "Go Fish: c"
h["c"].upcase! #=> "GO FISH: C"
h["d"] #=> "Go Fish: d"
h.keys #=> ["c", "d"]
static VALUE
rb_hash_s_ruby2_keywords_hash(VALUE dummy, VALUE hash)
{
Check_Type(hash, T_HASH);
hash = rb_hash_dup(hash);
RHASH(hash)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
return hash;
} Создаёт копию заданного словаря и добавляет флаг ruby2_keywords. Этот метод не для повседневного использования; отладка, исследование и некоторые действительно необходимые случаи, такие как десериализация аргументов.
h = {k: 1}
h = Hash.ruby2_keywords_hash(h)
def foo(k: 42)
k
end
foo(*[h]) #=> 1 with neither a warning or an error
static VALUE
rb_hash_s_ruby2_keywords_hash_p(VALUE dummy, VALUE hash)
{
Check_Type(hash, T_HASH);
return (RHASH(hash)->basic.flags & RHASH_PASS_AS_KEYWORDS) ? Qtrue : Qfalse;
} Проверяет, помечен ли заданный словарь методом Module#ruby2_keywords (или Proc#ruby2_keywords). Этот метод не для повседневного использования; отладка, исследование и некоторые действительно необходимые случаи, такие как сериализация аргументов.
ruby2_keywords def foo(*args)
Hash.ruby2_keywords_hash?(args.last)
end
foo(k: 1) #=> true
foo({k: 1}) #=> false
static VALUE
rb_hash_s_try_convert(VALUE dummy, VALUE hash)
{
return rb_check_hash_type(hash);
} Попытка преобразовать объект в словарь, используя метод to_hash. Возвращает преобразованный словарь или nil, если объект не может быть преобразован по какой-либо причине.
Hash.try_convert({1=>2}) # => {1=>2}
Hash.try_convert("1=>2") # => nil
Общедоступные методы экземпляров
static VALUE
rb_hash_lt(VALUE hash, VALUE other)
{
other = to_hash(other);
if (RHASH_SIZE(hash) >= RHASH_SIZE(other)) return Qfalse;
return hash_le(hash, other);
} Возвращает значение true , если hash является подмножеством other.
h1 = {a:1, b:2}
h2 = {a:1, b:2, c:3}
h1 < h2 #=> true
h2 < h1 #=> false
h1 < h1 #=> false
static VALUE
rb_hash_le(VALUE hash, VALUE other)
{
other = to_hash(other);
if (RHASH_SIZE(hash) > RHASH_SIZE(other)) return Qfalse;
return hash_le(hash, other);
} Возвращает значение true , если hash является подмножеством other или равно other.
h1 = {a:1, b:2}
h2 = {a:1, b:2, c:3}
h1 <= h2 #=> true
h2 <= h1 #=> false
h1 <= h1 #=> true
static VALUE
rb_hash_equal(VALUE hash1, VALUE hash2)
{
return hash_equal(hash1, hash2, FALSE);
} Равенство — Два хэша равны, если они содержат одинаковое количество ключей и если каждая пара «ключ-значение» равна (в соответствии с Object#==) соответствующим элементам в другом хэше.
h1 = { "a" => 1, "c" => 2 }
h2 = { 7 => 35, "c" => 2, "a" => 1 }
h3 = { "a" => 1, "c" => 2, 7 => 35 }
h4 = { "a" => 1, "d" => 2, "f" => 35 }
h1 == h2 #=> false
h2 == h3 #=> true
h3 == h4 #=> false
Порядок элементов хэшей не сравнивается.
h1 = { "a" => 1, "c" => 2 }
h2 = { "c" => 2, "a" => 1 }
h1 == h2 #=> true
static VALUE
rb_hash_gt(VALUE hash, VALUE other)
{
other = to_hash(other);
if (RHASH_SIZE(hash) <= RHASH_SIZE(other)) return Qfalse;
return hash_le(other, hash);
} Возвращает значение true , если other является подмножеством hash.
h1 = {a:1, b:2}
h2 = {a:1, b:2, c:3}
h1 > h2 #=> false
h2 > h1 #=> true
h1 > h1 #=> false
static VALUE
rb_hash_ge(VALUE hash, VALUE other)
{
other = to_hash(other);
if (RHASH_SIZE(hash) < RHASH_SIZE(other)) return Qfalse;
return hash_le(other, hash);
} Возвращает значение true , если other является подмножеством hash или равно hash.
h1 = {a:1, b:2}
h2 = {a:1, b:2, c:3}
h1 >= h2 #=> false
h2 >= h1 #=> true
h1 >= h1 #=> true
VALUE
rb_hash_aref(VALUE hash, VALUE key)
{
st_data_t val;
if (hash_stlike_lookup(hash, key, &val)) {
return (VALUE)val;
}
else {
return rb_hash_default_value(hash, key);
}
} Обращение к элементу — Возвращает объект value, соответствующий объекту key. Если не найдено, возвращает значение по умолчанию (см. Hash::new для подробностей).
h = { "a" => 100, "b" => 200 }
h["a"] #=> 100
h["c"] #=> nil
VALUE
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
int iter_lev = RHASH_ITER_LEV(hash);
rb_hash_modify(hash);
if (RHASH_TABLE_NULL_P(hash)) {
if (iter_lev > 0) no_new_key();
ar_alloc_table(hash);
}
if (RHASH_TYPE(hash) == &identhash || rb_obj_class(key) != rb_cString) {
RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset, val);
}
else {
RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset_str, val);
}
return val;
} Присвоение элемента
Связывает значение, заданное value , с ключом, заданным key .
h = { "a" => 100, "b" => 200 }
h["a"] = 9
h["c"] = 4
h #=> {"a"=>9, "b"=>200, "c"=>4}
h.store("d", 42) #=> 42
h #=> {"a"=>9, "b"=>200, "c"=>4, "d"=>42}
key не должен изменять своего значения во время использования в качестве ключа (ключ, представленный как unfrozen String , будет дублирован и заморожен).
a = "a"
b = "b".freeze
h = { a => 100, b => 200 }
h.key(100).equal? a #=> false
h.key(200).equal? b #=> true
static VALUE
rb_hash_any_p(int argc, VALUE *argv, VALUE hash)
{
VALUE args[2];
args[0] = Qfalse;
rb_check_arity(argc, 0, 1);
if (RHASH_EMPTY_P(hash)) return Qfalse;
if (argc) {
if (rb_block_given_p()) {
rb_warn("given block not used");
}
args[1] = argv[0];
rb_hash_foreach(hash, any_p_i_pattern, (VALUE)args);
}
else {
if (!rb_block_given_p()) {
/* yields pairs, never false */
return Qtrue;
}
if (rb_block_arity() > 1)
rb_hash_foreach(hash, any_p_i_fast, (VALUE)args);
else
rb_hash_foreach(hash, any_p_i, (VALUE)args);
}
return args[0];
} См. также Enumerable#any?
VALUE
rb_hash_assoc(VALUE hash, VALUE key)
{
st_table *table;
const struct st_hash_type *orighash;
VALUE args[2];
if (RHASH_EMPTY_P(hash)) return Qnil;
ar_force_convert_table(hash, __FILE__, __LINE__);
HASH_ASSERT(RHASH_ST_TABLE_P(hash));
table = RHASH_ST_TABLE(hash);
orighash = table->type;
if (orighash != &identhash) {
VALUE value;
struct reset_hash_type_arg ensure_arg;
struct st_hash_type assochash;
assochash.compare = assoc_cmp;
assochash.hash = orighash->hash;
table->type = &assochash;
args[0] = hash;
args[1] = key;
ensure_arg.hash = hash;
ensure_arg.orighash = orighash;
value = rb_ensure(lookup2_call, (VALUE)&args, reset_hash_type, (VALUE)&ensure_arg);
if (value != Qundef) return rb_assoc_new(key, value);
}
args[0] = key;
args[1] = Qnil;
rb_hash_foreach(hash, assoc_i, (VALUE)args);
return args[1];
} Ищет в хэше, сравнивая obj с ключом с использованием ==. Возвращает пару «ключ-значение» (массив из двух элементов) или nil , если совпадение не найдено. См. Array#assoc.
h = {"colors" => ["red", "blue", "green"],
"letters" => ["a", "b", "c" ]}
h.assoc("letters") #=> ["letters", ["a", "b", "c"]]
h.assoc("foo") #=> nil
VALUE
rb_hash_clear(VALUE hash)
{
rb_hash_modify_check(hash);
if (RHASH_ITER_LEV(hash) > 0) {
rb_hash_foreach(hash, clear_i, 0);
}
else if (RHASH_AR_TABLE_P(hash)) {
ar_clear(hash);
}
else {
st_clear(RHASH_ST_TABLE(hash));
}
return hash;
} Удаляет все пары «ключ-значение» из hsh.
h = { "a" => 100, "b" => 200 } #=> {"a"=>100, "b"=>200}
h.clear #=> {}
static VALUE
rb_hash_compact(VALUE hash)
{
VALUE result = rb_hash_new();
if (!RHASH_EMPTY_P(hash)) {
rb_hash_foreach(hash, set_if_not_nil, result);
}
return result;
} Возвращает новый хэш со удаленными парами/значениями nil.
h = { a: 1, b: false, c: nil }
h.compact #=> { a: 1, b: false }
h #=> { a: 1, b: false, c: nil }
static VALUE
rb_hash_compact_bang(VALUE hash)
{
st_index_t n;
rb_hash_modify_check(hash);
n = RHASH_SIZE(hash);
if (n) {
rb_hash_foreach(hash, delete_if_nil, hash);
if (n != RHASH_SIZE(hash))
return hash;
}
return Qnil;
} Удаляет все значения nil из хэша. Возвращает nil, если изменений не было, иначе возвращает хэш.
h = { a: 1, b: false, c: nil }
h.compact! #=> { a: 1, b: false }
static VALUE
rb_hash_compare_by_id(VALUE hash)
{
VALUE tmp;
st_table *identtable;
if (rb_hash_compare_by_id_p(hash)) return hash;
rb_hash_modify_check(hash);
ar_force_convert_table(hash, __FILE__, __LINE__);
HASH_ASSERT(RHASH_ST_TABLE_P(hash));
tmp = hash_alloc(0);
identtable = rb_init_identtable_with_size(RHASH_SIZE(hash));
RHASH_ST_TABLE_SET(tmp, identtable);
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
st_free_table(RHASH_ST_TABLE(hash));
RHASH_ST_TABLE_SET(hash, identtable);
RHASH_ST_CLEAR(tmp);
rb_gc_force_recycle(tmp);
return hash;
} Заставляет hsh сравнивать ключи по их идентичности, то есть будет считать абсолютно одинаковые объекты одинаковыми ключами.
h1 = { "a" => 100, "b" => 200, :c => "c" }
h1["a"] #=> 100
h1.compare_by_identity
h1.compare_by_identity? #=> true
h1["a".dup] #=> nil # different objects.
h1[:c] #=> "c" # same symbols are all same.
MJIT_FUNC_EXPORTED VALUE
rb_hash_compare_by_id_p(VALUE hash)
{
if (RHASH_ST_TABLE_P(hash) && RHASH_ST_TABLE(hash)->type == &identhash) {
return Qtrue;
}
else {
return Qfalse;
}
} Возвращает true , если hsh сравнивает ключи по их идентичности. Также см. Hash#compare_by_identity.
static VALUE
rb_hash_deconstruct_keys(VALUE hash, VALUE keys)
{
return hash;
} static VALUE
rb_hash_default(int argc, VALUE *argv, VALUE hash)
{
VALUE args[2], ifnone;
rb_check_arity(argc, 0, 1);
ifnone = RHASH_IFNONE(hash);
if (FL_TEST(hash, RHASH_PROC_DEFAULT)) {
if (argc == 0) return Qnil;
args[0] = hash;
args[1] = argv[0];
return rb_funcallv(ifnone, id_yield, 2, args);
}
return ifnone;
} Возвращает значение по умолчанию, значение, которое вернул бы hsh, если key не существует в hsh. Также см. Hash::new и Hash#default=.
h = Hash.new #=> {}
h.default #=> nil
h.default(2) #=> nil
h = Hash.new("cat") #=> {}
h.default #=> "cat"
h.default(2) #=> "cat"
h = Hash.new {|h,k| h[k] = k.to_i*10} #=> {}
h.default #=> nil
h.default(2) #=> 20
static VALUE
rb_hash_set_default(VALUE hash, VALUE ifnone)
{
rb_hash_modify_check(hash);
SET_DEFAULT(hash, ifnone);
return ifnone;
} Устанавливает значение по умолчанию, значение, возвращаемое для ключа, который не существует в хэше. Невозможно установить значение по умолчанию в виде Proc, который будет выполняться при каждом запросе ключа.
h = { "a" => 100, "b" => 200 }
h.default = "Go fish"
h["a"] #=> 100
h["z"] #=> "Go fish"
# This doesn't do what you might hope...
h.default = proc do |hash, key|
hash[key] = key + key
end
h[2] #=> #<Proc:0x401b3948@-:6>
h["cat"] #=> #<Proc:0x401b3948@-:6>
static VALUE
rb_hash_default_proc(VALUE hash)
{
if (FL_TEST(hash, RHASH_PROC_DEFAULT)) {
return RHASH_IFNONE(hash);
}
return Qnil;
} Если Hash::new был вызван с блоком, верните этот блок, иначе верните nil.
h = Hash.new {|h,k| h[k] = k*k } #=> {}
p = h.default_proc #=> #<Proc:0x401b3d08@-:1>
a = [] #=> []
p.call(a, 2)
a #=> [nil, nil, 4]
VALUE
rb_hash_set_default_proc(VALUE hash, VALUE proc)
{
VALUE b;
rb_hash_modify_check(hash);
if (NIL_P(proc)) {
SET_DEFAULT(hash, proc);
return proc;
}
b = rb_check_convert_type_with_id(proc, T_DATA, "Proc", idTo_proc);
if (NIL_P(b) || !rb_obj_is_proc(b)) {
rb_raise(rb_eTypeError,
"wrong default_proc type %s (expected Proc)",
rb_obj_classname(proc));
}
proc = b;
SET_PROC_DEFAULT(hash, proc);
return proc;
} Устанавливает процедуру по умолчанию, которая должна выполняться при каждом неудачном поиске ключа.
h.default_proc = proc do |hash, key| hash[key] = key + key end h[2] #=> 4 h["cat"] #=> "catcat"
static VALUE
rb_hash_delete_m(VALUE hash, VALUE key)
{
VALUE val;
rb_hash_modify_check(hash);
val = rb_hash_delete_entry(hash, key);
if (val != Qundef) {
return val;
}
else {
if (rb_block_given_p()) {
return rb_yield(key);
}
else {
return Qnil;
}
}
} Удаляет пару «ключ-значение» и возвращает значение из hsh, ключ которого равен key. Если ключ не найден, возвращает nil. Если задан необязательный блок кода и ключ не найден, передайте ключ и верните результат block.
h = { "a" => 100, "b" => 200 }
h.delete("a") #=> 100
h.delete("z") #=> nil
h.delete("z") { |el| "#{el} not found" } #=> "z not found"
VALUE
rb_hash_delete_if(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify_check(hash);
if (!RHASH_TABLE_EMPTY_P(hash)) {
rb_hash_foreach(hash, delete_if_i, hash);
}
return hash;
} Удаляет каждую пару «ключ-значение» из hsh, для которой block возвращает true.
Если блок не задан, вместо него возвращается перечисление.
h = { "a" => 100, "b" => 200, "c" => 300 }
h.delete_if {|key, value| key >= "b" } #=> {"a"=>100}
static VALUE
rb_hash_dig(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
self = rb_hash_aref(self, *argv);
if (!--argc) return self;
++argv;
return rb_obj_dig(argc, argv, self, Qnil);
} Извлекает вложенное значение, указанное последовательностью объектов key, вызывая dig на каждом шаге, возвращая nil , если любой промежуточный шаг является nil .
h = { foo: {bar: {baz: 1}}}
h.dig(:foo, :bar, :baz) #=> 1
h.dig(:foo, :zot, :xyz) #=> nil
g = { foo: [10, 11, 12] }
g.dig(:foo, 1) #=> 11
g.dig(:foo, 1, 0) #=> TypeError: Integer does not have #dig method
g.dig(:foo, :bar) #=> TypeError: no implicit conversion of Symbol into Integer
static VALUE
rb_hash_each_pair(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
if (rb_block_arity() > 1)
rb_hash_foreach(hash, each_pair_i_fast, 0);
else
rb_hash_foreach(hash, each_pair_i, 0);
return hash;
} Вызывает блок один раз для каждого ключа в хш, передавая пару ключ-значение в качестве параметров.
Если блок не задан, возвращается перечислитель вместо него.
h = { "a" => 100, "b" => 200 }
h.each {|key, value| puts "#{key} is #{value}" }
результат:
a is 100 b is 200
static VALUE
rb_hash_each_key(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_foreach(hash, each_key_i, 0);
return hash;
} Вызывает блок один раз для каждого ключа в хш, передавая ключ в качестве параметра.
Если блок не задан, возвращается перечислитель вместо него.
h = { "a" => 100, "b" => 200 }
h.each_key {|key| puts key }
результат:
a b
static VALUE
rb_hash_each_pair(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
if (rb_block_arity() > 1)
rb_hash_foreach(hash, each_pair_i_fast, 0);
else
rb_hash_foreach(hash, each_pair_i, 0);
return hash;
} Вызывает блок один раз для каждого ключа в хш, передавая пару ключ-значение в качестве параметров.
Если блок не задан, возвращается перечислитель вместо него.
h = { "a" => 100, "b" => 200 }
h.each {|key, value| puts "#{key} is #{value}" }
результат:
a is 100 b is 200
static VALUE
rb_hash_each_value(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_foreach(hash, each_value_i, 0);
return hash;
} Вызывает блок один раз для каждого ключа в хш, передавая значение в качестве параметра.
Если блок не задан, возвращается перечислитель вместо него.
h = { "a" => 100, "b" => 200 }
h.each_value {|value| puts value }
результат:
100 200
static VALUE
rb_hash_empty_p(VALUE hash)
{
return RHASH_EMPTY_P(hash) ? Qtrue : Qfalse;
} Возвращает true , если хш не содержит пар ключ-значение.
{}.empty? #=> true
static VALUE
rb_hash_eql(VALUE hash1, VALUE hash2)
{
return hash_equal(hash1, hash2, TRUE);
} Возвращает true , если хэш и other — оба хэша с одинаковым содержанием. Порядок элементов хэшей не сравнивается.
static VALUE
rb_hash_invert(VALUE hash)
{
VALUE h = rb_hash_new_with_size(RHASH_SIZE(hash));
rb_hash_foreach(hash, rb_hash_invert_i, h);
return h;
} Возвращает новый хэш, созданный путём использования значений hsh в качестве ключей и ключей в качестве значений. Если ключ с тем же значением уже существует в hsh, то будет использоваться последний определённый ключ, более ранние значения будут отброшены.
h = { "n" => 100, "m" => 100, "y" => 300, "d" => 200, "a" => 0 }
h.invert #=> {0=>"a", 100=>"m", 200=>"d", 300=>"y"}
Если ключа с тем же значением нет, Hash#invert является инволютивным.
h = { a: 1, b: 3, c: 4 }
h.invert.invert == h #=> true
Условие, отсутствие ключа с тем же значением, может быть проверено путём сравнения размера инвертированного хэша.
# no key with the same value
h = { a: 1, b: 3, c: 4 }
h.size == h.invert.size #=> true
# two (or more) keys has the same value
h = { a: 1, b: 3, c: 1 }
h.size == h.invert.size #=> false
VALUE
rb_hash_keep_if(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify_check(hash);
if (!RHASH_TABLE_EMPTY_P(hash)) {
rb_hash_foreach(hash, keep_if_i, hash);
}
return hash;
} Удаляет каждую пару ключ-значение из hsh, для которой block возвращает false.
Если блок не указан, вместо него возвращается перечислитель.
См. также Hash#select!.
static VALUE
rb_hash_key(VALUE hash, VALUE value)
{
VALUE args[2];
args[0] = value;
args[1] = Qnil;
rb_hash_foreach(hash, key_i, (VALUE)args);
return args[1];
} Возвращает ключ появления заданного значения. Если значение не найдено, возвращает nil.
h = { "a" => 100, "b" => 200, "c" => 300, "d" => 300 }
h.key(200) #=> "b"
h.key(300) #=> "c"
h.key(999) #=> nil
MJIT_FUNC_EXPORTED VALUE
rb_hash_has_key(VALUE hash, VALUE key)
{
if (hash_stlike_lookup(hash, key, NULL)) {
return Qtrue;
}
else {
return Qfalse;
}
} Возвращает true, если заданный ключ присутствует в hsh.
h = { "a" => 100, "b" => 200 }
h.has_key?("a") #=> true
h.has_key?("z") #=> false
Обратите внимание, что include? и member? не проверяют равенство членов, используя == так же, как и другие перечислители.
См. также Enumerable#include?
MJIT_FUNC_EXPORTED VALUE
rb_hash_keys(VALUE hash)
{
st_index_t size = RHASH_SIZE(hash);
VALUE keys = rb_ary_new_capa(size);
if (size == 0) return keys;
if (ST_DATA_COMPATIBLE_P(VALUE)) {
RARRAY_PTR_USE_TRANSIENT(keys, ptr, {
if (RHASH_AR_TABLE_P(hash)) {
size = ar_keys(hash, ptr, size);
}
else {
st_table *table = RHASH_ST_TABLE(hash);
size = st_keys(table, ptr, size);
}
});
rb_gc_writebarrier_remember(keys);
rb_ary_set_len(keys, size);
}
else {
rb_hash_foreach(hash, keys_i, keys);
}
return keys;
} Возвращает новый массив, заполненный ключами из этого хэша. См. также Hash#values.
h = { "a" => 100, "b" => 200, "c" => 300, "d" => 400 }
h.keys #=> ["a", "b", "c", "d"]
VALUE
rb_hash_size(VALUE hash)
{
return INT2FIX(RHASH_SIZE(hash));
} Возвращает количество пар ключ-значение в хэше.
h = { "d" => 100, "a" => 200, "v" => 300, "e" => 400 }
h.size #=> 4
h.delete("a") #=> 200
h.size #=> 3
h.length #=> 3
Hash#length является псевдонимом для Hash#size.
MJIT_FUNC_EXPORTED VALUE
rb_hash_has_key(VALUE hash, VALUE key)
{
if (hash_stlike_lookup(hash, key, NULL)) {
return Qtrue;
}
else {
return Qfalse;
}
} Возвращает true если заданный ключ присутствует в hsh.
h = { "a" => 100, "b" => 200 }
h.has_key?("a") #=> true
h.has_key?("z") #=> false
Обратите внимание, что include? и member? не проверяют равенство членов, используя == так же, как и другие перечислители.
См. также Enumerable#include?
VALUE
rb_hash_size(VALUE hash)
{
return INT2FIX(RHASH_SIZE(hash));
} Возвращает количество пар ключ-значение в хэше.
h = { "d" => 100, "a" => 200, "v" => 300, "e" => 400 }
h.size #=> 4
h.delete("a") #=> 200
h.size #=> 3
h.length #=> 3
Hash#length является псевдонимом для Hash#size.
static VALUE
rb_hash_slice(int argc, VALUE *argv, VALUE hash)
{
int i;
VALUE key, value, result;
if (argc == 0 || RHASH_EMPTY_P(hash)) {
return rb_hash_new();
}
result = rb_hash_new_with_size(argc);
for (i = 0; i < argc; i++) {
key = argv[i];
value = rb_hash_lookup2(hash, key, Qundef);
if (value != Qundef)
rb_hash_aset(result, key, value);
}
return result;
} Возвращает хэш, содержащий только указанные ключи и их значения.
h = { a: 100, b: 200, c: 300 }
h.slice(:a) #=> {:a=>100}
h.slice(:b, :c, :d) #=> {:b=>200, :c=>300}
VALUE
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
int iter_lev = RHASH_ITER_LEV(hash);
rb_hash_modify(hash);
if (RHASH_TABLE_NULL_P(hash)) {
if (iter_lev > 0) no_new_key();
ar_alloc_table(hash);
}
if (RHASH_TYPE(hash) == &identhash || rb_obj_class(key) != rb_cString) {
RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset, val);
}
else {
RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset_str, val);
}
return val;
} Присвоение элемента
Связывает значение, заданное value, с ключом, заданным key.
h = { "a" => 100, "b" => 200 }
h["a"] = 9
h["c"] = 4
h #=> {"a"=>9, "b"=>200, "c"=>4}
h.store("d", 42) #=> 42
h #=> {"a"=>9, "b"=>200, "c"=>4, "d"=>42}
Значение key не должно изменяться во время использования в качестве ключа (ключ, представляющий unfrozen String, будет дублирован и заморожен).
a = "a"
b = "b".freeze
h = { a => 100, b => 200 }
h.key(100).equal? a #=> false
h.key(200).equal? b #=> true
static VALUE
rb_hash_to_a(VALUE hash)
{
VALUE ary;
ary = rb_ary_new_capa(RHASH_SIZE(hash));
rb_hash_foreach(hash, to_a_i, ary);
return ary;
} Преобразует hsh в вложенный массив [ массивов ключ, значение ].
h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 }
h.to_a #=> [["c", 300], ["a", 100], ["d", 400]]
static VALUE
rb_hash_to_h(VALUE hash)
{
if (rb_block_given_p()) {
return rb_hash_to_h_block(hash);
}
if (rb_obj_class(hash) != rb_cHash) {
const VALUE flags = RBASIC(hash)->flags;
hash = hash_dup(hash, rb_cHash, flags & RHASH_PROC_DEFAULT);
}
return hash;
} Возвращает self. Если вызов осуществляется для подкласса Hash, преобразует получатель в объект Hash.
Если задан блок, результаты выполнения блока для каждой пары получателя будут использоваться как пары.
static VALUE
rb_hash_to_hash(VALUE hash)
{
return hash;
} Возвращает self.
static VALUE
rb_hash_to_proc(VALUE hash)
{
return rb_func_proc_new(hash_proc_call, hash);
} Возвращает Proc, который сопоставляет ключи со значениями.
h = {a:1, b:2}
hp = h.to_proc
hp.call(:a) #=> 1
hp.call(:b) #=> 2
hp.call(:c) #=> nil
[:a, :b, :c].map(&h) #=> [1, 2, nil]
static VALUE
rb_hash_transform_keys(VALUE hash)
{
VALUE result;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
result = rb_hash_new();
if (!RHASH_EMPTY_P(hash)) {
rb_hash_foreach(hash, transform_keys_i, result);
}
return result;
} Возвращает новый хэш с результатами выполнения блока один раз для каждого ключа. Этот метод не изменяет значения.
h = { a: 1, b: 2, c: 3 }
h.transform_keys {|k| k.to_s } #=> { "a" => 1, "b" => 2, "c" => 3 }
h.transform_keys(&:to_s) #=> { "a" => 1, "b" => 2, "c" => 3 }
h.transform_keys.with_index {|k, i| "#{k}.#{i}" }
#=> { "a.0" => 1, "b.1" => 2, "c.2" => 3 }
Если блок не задан, возвращается перечислитель.
static VALUE
rb_hash_transform_keys_bang(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify_check(hash);
if (!RHASH_TABLE_EMPTY_P(hash)) {
long i;
VALUE pairs = rb_hash_flatten(0, NULL, hash);
rb_hash_clear(hash);
for (i = 0; i < RARRAY_LEN(pairs); i += 2) {
VALUE key = RARRAY_AREF(pairs, i), new_key = rb_yield(key),
val = RARRAY_AREF(pairs, i+1);
rb_hash_aset(hash, new_key, val);
}
}
return hash;
} Вызывает заданный блок один раз для каждого ключа в hsh, заменяя его новым ключом, возвращенным блоком, и затем возвращает hsh. Этот метод не изменяет значения.
h = { a: 1, b: 2, c: 3 }
h.transform_keys! {|k| k.to_s } #=> { "a" => 1, "b" => 2, "c" => 3 }
h.transform_keys!(&:to_sym) #=> { a: 1, b: 2, c: 3 }
h.transform_keys!.with_index {|k, i| "#{k}.#{i}" }
#=> { "a.0" => 1, "b.1" => 2, "c.2" => 3 }
Если блок не задан, возвращается перечислитель.
static VALUE
rb_hash_transform_values(VALUE hash)
{
VALUE result;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
result = hash_copy(hash_alloc(rb_cHash), hash);
SET_DEFAULT(result, Qnil);
if (!RHASH_EMPTY_P(hash)) {
rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, result);
}
return result;
} Возвращает новый хэш с результатами выполнения блока один раз для каждого значения. Этот метод не изменяет ключи.
h = { a: 1, b: 2, c: 3 }
h.transform_values {|v| v * v + 1 } #=> { a: 2, b: 5, c: 10 }
h.transform_values(&:to_s) #=> { a: "1", b: "2", c: "3" }
h.transform_values.with_index {|v, i| "#{v}.#{i}" }
#=> { a: "1.0", b: "2.1", c: "3.2" }
Если блок не задан, возвращается перечислитель.
static VALUE
rb_hash_transform_values_bang(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify_check(hash);
if (!RHASH_TABLE_EMPTY_P(hash)) {
rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash);
}
return hash;
} Вызывает заданный блок один раз для каждого значения в hsh, заменяя его новым значением, возвращенным блоком, и затем возвращает hsh. Этот метод не изменяет ключи.
h = { a: 1, b: 2, c: 3 }
h.transform_values! {|v| v * v + 1 } #=> { a: 2, b: 5, c: 10 }
h.transform_values!(&:to_s) #=> { a: "2", b: "5", c: "10" }
h.transform_values!.with_index {|v, i| "#{v}.#{i}" }
#=> { a: "2.0", b: "5.1", c: "10.2" }
Если блок не задан, возвращается перечислитель.
static VALUE
rb_hash_update(int argc, VALUE *argv, VALUE self)
{
int i;
bool block_given = rb_block_given_p();
rb_hash_modify(self);
for (i = 0; i < argc; i++){
VALUE hash = to_hash(argv[i]);
if (block_given) {
rb_hash_foreach(hash, rb_hash_update_block_i, self);
}
else {
rb_hash_foreach(hash, rb_hash_update_i, self);
}
}
return self;
} Добавляет содержимое заданных хэшей к получателю.
Если блок не задан, записи с дублирующимися ключами перезаписываются значениями из каждого хэша последовательно, в противном случае значение для каждого дублирующегося ключа определяется путем вызова блока с ключом, его значением в получателе и его значением в каждом хэше.
h1 = { "a" => 100, "b" => 200 }
h1.merge! #=> {"a"=>100, "b"=>200}
h1 #=> {"a"=>100, "b"=>200}
h1 = { "a" => 100, "b" => 200 }
h2 = { "b" => 246, "c" => 300 }
h1.merge!(h2) #=> {"a"=>100, "b"=>246, "c"=>300}
h1 #=> {"a"=>100, "b"=>246, "c"=>300}
h1 = { "a" => 100, "b" => 200 }
h2 = { "b" => 246, "c" => 300 }
h3 = { "b" => 357, "d" => 400 }
h1.merge!(h2, h3)
#=> {"a"=>100, "b"=>357, "c"=>300, "d"=>400}
h1 #=> {"a"=>100, "b"=>357, "c"=>300, "d"=>400}
h1 = { "a" => 100, "b" => 200 }
h2 = { "b" => 246, "c" => 300 }
h3 = { "b" => 357, "d" => 400 }
h1.merge!(h2, h3) {|key, v1, v2| v1 }
#=> {"a"=>100, "b"=>200, "c"=>300, "d"=>400}
h1 #=> {"a"=>100, "b"=>200, "c"=>300, "d"=>400}
Hash#update является псевдонимом для Hash#merge!.
static VALUE
rb_hash_has_value(VALUE hash, VALUE val)
{
VALUE data[2];
data[0] = Qfalse;
data[1] = val;
rb_hash_foreach(hash, rb_hash_search_value, (VALUE)data);
return data[0];
} Возвращает true если заданное значение присутствует для некоторого ключа в hsh.
h = { "a" => 100, "b" => 200 }
h.value?(100) #=> true
h.value?(999) #=> false
VALUE
rb_hash_values(VALUE hash)
{
VALUE values;
st_index_t size = RHASH_SIZE(hash);
values = rb_ary_new_capa(size);
if (size == 0) return values;
if (ST_DATA_COMPATIBLE_P(VALUE)) {
if (RHASH_AR_TABLE_P(hash)) {
rb_gc_writebarrier_remember(values);
RARRAY_PTR_USE_TRANSIENT(values, ptr, {
size = ar_values(hash, ptr, size);
});
}
else if (RHASH_ST_TABLE_P(hash)) {
st_table *table = RHASH_ST_TABLE(hash);
rb_gc_writebarrier_remember(values);
RARRAY_PTR_USE_TRANSIENT(values, ptr, {
size = st_values(table, ptr, size);
});
}
rb_ary_set_len(values, size);
}
else {
rb_hash_foreach(hash, values_i, values);
}
return values;
} Возвращает новый массив, заполненный значениями из hsh. См. также Hash#keys.
h = { "a" => 100, "b" => 200, "c" => 300 }
h.values #=> [100, 200, 300]
VALUE
rb_hash_values_at(int argc, VALUE *argv, VALUE hash)
{
VALUE result = rb_ary_new2(argc);
long i;
for (i=0; i<argc; i++) {
rb_ary_push(result, rb_hash_aref(hash, argv[i]));
}
return result;
} Возвращает массив, содержащий значения, связанные с заданными ключами. См. также Hash.select.
h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" }
h.values_at("cow", "cat") #=> ["bovine", "feline"]
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.