класс Hash
A Hash сопоставляет каждый из своих уникальных ключей со специфическим значением.
A Hash имеет определенное сходство с Array, но:
Hash Синтаксис данных
Старый синтаксис для Hash данных использует «стрелку хэша», =>:
h = {:foo => 0, :bar => 1, :baz => 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
В качестве альтернативы, но только для ключа Hash, который является Symbol, можно использовать новый синтаксис в стиле JSON, где каждое простое слово становится символом:
h = {foo: 0, bar: 1, baz: 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
Вы также можете использовать String вместо простого слова:
h = {'foo': 0, 'bar': 1, 'baz': 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
И вы можете смешивать стили:
h = {foo: 0, :bar => 1, 'baz': 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
Но попытка использовать синтаксис в стиле JSON для ключа, который не является простым словом или строкой, является ошибкой:
# Raises SyntaxError (syntax error, unexpected ':', expecting =>):
h = {0: 'zero'} Значение Hash можно опустить, что означает, что значение будет извлечено из контекста по имени ключа:
x = 0
y = 100
h = {x:, y:}
h # => {:x=>0, :y=>100}
Общие применения
Вы можете использовать Hash для присвоения имен объектам:
person = {name: 'Matz', language: 'Ruby'}
person # => {:name=>"Matz", :language=>"Ruby"}
Вы можете использовать Hash для присвоения имен аргументам метода:
def some_method(hash)
p hash
end
some_method({foo: 0, bar: 1, baz: 2}) # => {:foo=>0, :bar=>1, :baz=>2}
Примечание: когда последним аргументом в вызове метода является Hash, фигурные скобки можно опустить:
some_method(foo: 0, bar: 1, baz: 2) # => {:foo=>0, :bar=>1, :baz=>2}
Вы можете использовать Hash для инициализации объекта:
class Dev
attr_accessor :name, :language
def initialize(hash)
self.name = hash[:name]
self.language = hash[:language]
end
end
matz = Dev.new(name: 'Matz', language: 'Ruby')
matz # => #<Dev: @name="Matz", @language="Ruby">
Создание Hash
Вы можете явно создать объект Hash с помощью:
Вы можете преобразовать определенные объекты в хэши с помощью:
-
Метода
Hash.
Вы можете создать Hash, вызвав метод Hash.new.
Создать пустой Hash:
h = Hash.new
h # => {}
h.class # => Hash
Вы можете создать Hash, вызвав метод Hash.[].
Создать пустой Hash:
h = Hash[]
h # => {}
Создать Hash с начальными записями:
h = Hash[foo: 0, bar: 1, baz: 2]
h # => {:foo=>0, :bar=>1, :baz=>2}
Вы можете создать Hash, используя его литеральную форму (фигурные скобки).
Создать пустой Hash:
h = {}
h # => {}
Создать Hash с начальными записями:
h = {foo: 0, bar: 1, baz: 2}
h # => {:foo=>0, :bar=>1, :baz=>2}
Hash Основы значений
Самый простой способ получить значение Hash (метод экземпляра []):
h = {foo: 0, bar: 1, baz: 2}
h[:foo] # => 0
Самый простой способ создать или обновить значение Hash (метод экземпляра []=):
h = {foo: 0, bar: 1, baz: 2}
h[:bat] = 3 # => 3
h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
h[:foo] = 4 # => 4
h # => {:foo=>4, :bar=>1, :baz=>2, :bat=>3}
Самый простой способ удалить запись Hash (метод экземпляра delete):
h = {foo: 0, bar: 1, baz: 2}
h.delete(:bar) # => 1
h # => {:foo=>0, :baz=>2}
Порядок записей
Объект Hash отображает записи в порядке их создания. Это наблюдается в:
-
Итеративных методах, таких как
each,each_key,each_pair,each_value. -
Других методах, чувствительных к порядку, таких как
shift,keys,values. -
Строке
String, возвращаемой методомinspect.
У нового Hash начальный порядок определяется заданными записями:
h = Hash[foo: 0, bar: 1]
h # => {:foo=>0, :bar=>1}
Новые записи добавляются в конец:
h[:baz] = 2
h # => {:foo=>0, :bar=>1, :baz=>2}
Обновление значения не влияет на порядок:
h[:baz] = 3
h # => {:foo=>0, :bar=>1, :baz=>3}
Но повторное создание удаленной записи может повлиять на порядок:
h.delete(:foo)
h[:foo] = 5
h # => {:bar=>1, :baz=>3, :foo=>5}
Hash Ключи
Hash Равенство ключей
Два объекта рассматриваются как один и тот же ключ хэша, когда их значение hash идентично, и два объекта eql? друг другу.
Модификация активного ключа Hash
Модификация ключа Hash во время его использования повреждает индекс хэша.
Этот Hash имеет ключи, которые являются массивами:
a0 = [ :foo, :bar ]
a1 = [ :baz, :bat ]
h = {a0 => 0, a1 => 1}
h.include?(a0) # => true
h[a0] # => 0
a0.hash # => 110002110
Модификация элемента массива a0[0] изменяет его значение хэша:
a0[0] = :bam a0.hash # => 1069447059
И повреждает индекс Hash:
h.include?(a0) # => false h[a0] # => nil
Вы можете восстановить индекс хэша, используя метод rehash:
h.rehash # => {[:bam, :bar]=>0, [:baz, :bat]=>1}
h.include?(a0) # => true
h[a0] # => 0
Ключ String всегда безопасен. Это происходит потому, что не-замороженный String, переданный в качестве ключа, будет заменен дублированной и замороженной строкой:
s = 'foo'
s.frozen? # => false
h = {s => 0}
first_key = h.keys.first
first_key.frozen? # => true
Пользовательские ключи Hash
Чтобы быть используемыми в качестве ключей Hash, объекты должны реализовывать методы hash и eql?. Примечание: это требование не применяется, если Hash использует compare_by_identity, так как сравнение в этом случае будет основываться на идентификаторе объекта ключа, а не на hash и eql?.
Object определяет базовую реализацию для hash и eq? , что делает каждый объект уникальным ключом. Как правило, пользовательские классы захотят переопределить эти методы для предоставления осмысленного поведения или, например, унаследовать от Struct, который имеет полезные определения для них.
Типичная реализация hash основана на данных объекта, а eql? обычно является псевдонимом переопределенного метода ==:
class Book
attr_reader :author, :title
def initialize(author, title)
@author = author
@title = title
end
def ==(other)
self.class === other &&
other.author == @author &&
other.title == @title
end
alias eql? ==
def hash
[self.class, @author, @title].hash
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
Значения по умолчанию
Методы [], values_at и dig должны возвращать значение, связанное с определенным ключом. Если такой ключ не найден, это значение будет определяться его функцией по умолчанию (если она есть) или же значением по умолчанию (по умолчанию «nil»).
Вы можете получить значение по умолчанию с помощью метода default:
h = Hash.new h.default # => nil
Вы можете установить значение по умолчанию, передав аргумент методу Hash.new или с помощью метода default=
h = Hash.new(-1) h.default # => -1 h.default = 0 h.default # => 0
Это значение по умолчанию возвращается для [], values_at и dig, когда ключ не найден:
counts = {foo: 42}
counts.default # => nil (default)
counts[:foo] = 42
counts[:bar] # => nil
counts.default = 0
counts[:bar] # => 0
counts.values_at(:foo, :bar, :baz) # => [42, 0, 0]
counts.dig(:bar) # => 0
Обратите внимание, что значение по умолчанию используется без дублирования. Не рекомендуется устанавливать значение по умолчанию для изменяемого объекта:
synonyms = Hash.new([]) synonyms[:hello] # => [] synonyms[:hello] << :hi # => [:hi], but this mutates the default! synonyms.default # => [:hi] synonyms[:world] << :universe synonyms[:world] # => [:hi, :universe], oops synonyms.keys # => [], oops
Для использования изменяемого объекта в качестве значения по умолчанию рекомендуется использовать функцию по умолчанию
Функция по умолчанию Proc
Когда функция по умолчанию для Hash установлена (т. е., не nil), значение по умолчанию, возвращаемое методом [], определяется только функцией по умолчанию.
Вы можете получить функцию по умолчанию с помощью метода default_proc:
h = Hash.new h.default_proc # => nil
Вы можете установить функцию по умолчанию, вызвав Hash.new с блоком или вызвав метод default_proc=
h = Hash.new { |hash, key| "Default value for #{key}" }
h.default_proc.class # => Proc
h.default_proc = proc { |hash, key| "Default value for #{key.inspect}" }
h.default_proc.class # => Proc
Когда функция по умолчанию установлена (т. е., не nil) и вызван метод [] с несуществующим ключом, [] вызывает функцию по умолчанию с объектом Hash и отсутствующим ключом, а затем возвращает возвращаемое значение функции:
h = Hash.new { |hash, key| "Default value for #{key}" }
h[:nosuch] # => "Default value for nosuch"
Обратите внимание, что в примере выше не создается запись для ключа :nosuch:
h.include?(:nosuch) # => false
Однако сама функция может добавить новую запись:
synonyms = Hash.new { |hash, key| hash[key] = [] }
synonyms.include?(:hello) # => false
synonyms[:hello] << :hi # => [:hi]
synonyms[:world] << :universe # => [:universe]
synonyms.keys # => [:hello, :world]
Обратите внимание, что установка функции по умолчанию очищает значение по умолчанию и наоборот.
Следует помнить, что функция по умолчанию, которая изменяет хэш, не является потокобезопасной в том смысле, что несколько потоков могут одновременно обращаться к функции по умолчанию для одного и того же ключа.
Что здесь
Прежде всего, что есть в другом месте. Класс Hash:
-
Унаследован от класса Объект.
-
Включает модуль Enumerable, который предоставляет десятки дополнительных методов.
Здесь класс Hash предоставляет методы, полезные для:
Класс Hash также включает методы из модуля Enumerable.
Методы для создания Hash
-
::[]: Возвращает новый хеш, заполненный заданными объектами. -
::new: Возвращает новый пустой хеш. -
::try_convert: Возвращает новый хеш, созданный из заданного объекта.
Методы для установки состояния Hash
-
compare_by_identity: Устанавливаетselfдля учета только идентичности при сравнении ключей. -
default=: Устанавливает значение по умолчанию. -
default_proc=: Устанавливает процедуру по умолчанию. -
rehash: Перестраивает хеш-таблицу путем пересчета хеш-индекса для каждого ключа.
Методы для запроса
-
any?: Возвращает, удовлетворяет ли какой-либо элемент заданному критерию. -
compare_by_identity?: Возвращает, учитывает ли хеш только идентичность при сравнении ключей. -
default: Возвращает значение по умолчанию или значение по умолчанию для заданного ключа. -
default_proc: Возвращает процедуру по умолчанию. -
empty?: Возвращает, пуст ли хеш. -
eql?: Возвращает, равен ли заданный объектself. -
hash: Возвращает целочисленный хеш-код. -
has_value?(псевдонимvalue?): Возвращает, является ли заданный объект значением вself. -
include?(псевдонимhas_key?,member?,key?): Возвращает, является ли заданный объект ключом вself.
Методы для сравнения
-
<: Возвращает, является лиselfсобственным подмножеством заданного объекта. -
<=: Возвращает, является лиselfподмножеством заданного объекта. -
==: Возвращает, равен ли заданный объектself. -
>: Возвращает, является лиselfсобственным надмножеством заданного объекта. -
>=: Возвращает, является лиselfнадмножеством заданного объекта.
Методы для извлечения
-
[]: Возвращает значение, связанное с заданным ключом. -
assoc: Возвращает массив из двух элементов, содержащий заданный ключ и его значение. -
dig: Возвращает объект во вложенных объектах, указанный заданным ключом и дополнительными аргументами. -
fetch: Возвращает значение для заданного ключа. -
fetch_values: Возвращает массив, содержащий значения, связанные с заданными ключами. -
key: Возвращает ключ для первой найденной записи с заданным значением. -
keys: Возвращает массив, содержащий все ключи вself. -
rassoc: Возвращает массив из двух элементов, состоящий из ключа и значения первой найденной записи с заданным значением. -
values: Возвращает массив, содержащий все значения вself/ -
values_at: Возвращает массив, содержащий значения для заданных ключей.
Методы для назначения
-
[]=(псевдонимstore): Связывает заданный ключ с заданным значением. -
merge: Возвращает хеш, образованный путем слияния каждого заданного хеша в копиюself. -
update(псевдонимmerge!): Сливает каждый заданный хеш вself. -
replace(псевдонимinitialize_copy): Заменяет все содержимоеselfсодержимым заданного хеша.
Методы для удаления
Эти методы удаляют записи из self:
-
clear: Удаляет все записи изself. -
compact!: Удаляет все записи со значениемnilизself. -
delete: Удаляет запись для заданного ключа. -
delete_if: Удаляет записи, выбранные заданным блоком. -
select!(псевдонимfilter!): Оставляет только те записи, которые выбраны заданным блоком. -
keep_if: Оставляет только те записи, которые выбраны заданным блоком. -
reject!: Удаляет записи, выбранные заданным блоком. -
shift: Удаляет и возвращает первую запись.
Эти методы возвращают копию self с удаленными записями:
-
compact: Возвращает копиюselfсо всеми удаленными записями со значениемnil. -
except: Возвращает копиюselfс удаленными записями для указанных ключей. -
select(псевдонимfilter): Возвращает копиюselfтолько с теми записями, которые выбраны заданным блоком. -
reject: Возвращает копиюselfс удаленными записями, как указано заданным блоком. -
slice: Возвращает хеш, содержащий записи для заданных ключей.
Методы для итерации
-
each_pair(псевдонимeach): Вызывает заданный блок для каждой пары ключ-значение. -
each_key: Вызывает заданный блок для каждого ключа. -
each_value: Вызывает заданный блок для каждого значения.
Методы для преобразования
-
inspect(псевдонимto_s): Возвращает новыйString, содержащий записи хеша. -
to_a: Возвращает новый массив массивов из двух элементов; каждый вложенный массив содержит пару ключ-значение изself. -
to_h: Возвращаетselfесли этоHash; если это подклассHash, возвращаетHash, содержащий записи изself. -
to_hash: Возвращаетself. -
to_proc: Возвращает proc, который отображает заданный ключ на его значение.
Методы для преобразования ключей и значений
-
transform_keys: Возвращает копиюselfс изменёнными ключами. -
transform_keys!: Изменяет ключи вself. -
transform_values: Возвращает копиюselfс изменёнными значениями. -
transform_values!: Изменяет значения вself.
Другие методы
Методы публичного класса
Исходный код
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)) {
if (!RHASH_EMPTY_P(tmp) && rb_hash_compare_by_id_p(tmp)) {
/* hash_copy for non-empty hash will copy compare_by_identity
flag, but we don't want it copied. Work around by
converting hash to flattened array and using that. */
tmp = rb_hash_to_a(tmp);
}
else {
hash = hash_alloc(klass);
if (!RHASH_EMPTY_P(tmp))
hash_copy(hash, tmp);
return hash;
}
}
else {
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;
} Возвращает новый объект Hash, заполненный указанными объектами, если таковые имеются. См. Hash::new.
Без аргумента возвращает новый пустой Hash.
Если единственным аргументом является Hash, возвращает новый Hash, заполненный записями из данного Hash, исключая значение по умолчанию или процедуру.
h = {foo: 0, bar: 1, baz: 2}
Hash[h] # => {:foo=>0, :bar=>1, :baz=>2}
Если единственным аргументом является массив Array из массивов по 2 элемента, возвращает новый Hash, где каждый массив по 2 элемента образует запись ключ-значение:
Hash[ [ [:foo, 0], [:bar, 1] ] ] # => {:foo=>0, :bar=>1}
Если количество аргументов чётное, возвращает новый Hash, где каждая последующая пара аргументов становится записью ключ-значение:
Hash[:foo, 0, :bar, 1] # => {:foo=>0, :bar=>1}
Вызывает исключение, если список аргументов не соответствует ни одному из вышеперечисленных вариантов.
Исходный код
# File hash.rb, line 37 def initialize(ifnone = (ifnone_unset = true), capacity: 0, &block) Primitive.rb_hash_init(capacity, ifnone_unset, ifnone, block) end
Возвращает новый пустой объект Hash.
Начальное значение по умолчанию и начальная процедура по умолчанию для нового хэша зависят от того, какая форма использовалась выше. См. Значения по умолчанию.
Если не указан ни аргумент, ни блок, инициализирует значение по умолчанию и процедуру по умолчанию к nil:
h = Hash.new h.default # => nil h.default_proc # => nil
Если аргумент default_value указан, но блок нет, инициализирует значение по умолчанию заданным default_value и процедуру по умолчанию к nil:
h = Hash.new(false) h.default # => false h.default_proc # => nil
Если блок указан, но не default_value, сохраняет блок в качестве процедуры по умолчанию и устанавливает значение по умолчанию к nil:
h = Hash.new {|hash, key| "Default value for #{key}" }
h.default # => nil
h.default_proc.class # => Proc
h[:nosuch] # => "Default value for nosuch"
Если указаны и блок, и default_value, выбрасывает ArgumentError.
Если необязательный ключевой аргумент capacity указан, хэш будет выделен с достаточной ёмкостью для размещения такого количества ключей без необходимости перераспределения.
Исходный код
static VALUE
rb_hash_s_ruby2_keywords_hash(VALUE dummy, VALUE hash)
{
Check_Type(hash, T_HASH);
VALUE tmp = rb_hash_dup(hash);
if (RHASH_EMPTY_P(hash) && rb_hash_compare_by_id_p(hash)) {
rb_hash_compare_by_id(tmp);
}
RHASH(tmp)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
return tmp;
} Создаёт дубликат заданного хэша и добавляет флаг 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 RBOOL(RHASH(hash)->basic.flags & RHASH_PASS_AS_KEYWORDS);
} Проверяет, помечен ли заданный хэш флагом 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);
} Если obj является объектом Hash, возвращает obj.
В противном случае, если obj отвечает на :to_hash, вызывает obj.to_hash и возвращает результат.
Возвращает nil если obj не отвечает на :to_hash
Вызывает исключение, если obj.to_hash не возвращает объект Hash.
Общедоступные методы экземпляров
Исходный код
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_hash, и false в противном случае:
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_hash, и false в противном случае:
false Исходный код
static VALUE
rb_hash_equal(VALUE hash1, VALUE hash2)
{
return hash_equal(hash1, hash2, FALSE);
} Возвращает true, если все следующие условия верны:
-
objectявляется объектомHash. -
hashиobjectимеют одинаковые ключи (независимо от порядка). -
Для каждого ключа
key,hash[key] == object[key].
В противном случае возвращает false.
Равность:
h1 = {foo: 0, bar: 1, baz: 2}
h2 = {foo: 0, bar: 1, baz: 2}
h1 == h2 # => true
h3 = {baz: 2, bar: 1, foo: 0}
h1 == h3 # => 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, если hash является собственным надмножеством other_hash, и false в противном случае:
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, если hash является надмножеством other_hash, и false в противном случае:
false Исходный код
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);
}
} Возвращает значение, связанное с заданным ключом, если он найден:
h = {foo: 0, bar: 1, baz: 2}
h[:foo] # => 0
Если ключ не найден, возвращает значение по умолчанию (см. Значения по умолчанию):
h = {foo: 0, bar: 1, baz: 2}
h[:nosuch] # => nil
Исходный код
VALUE
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
bool iter_p = hash_iterating_p(hash);
rb_hash_modify(hash);
if (!RHASH_STRING_KEY_P(hash, key)) {
RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset, val);
}
else {
RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset_str, val);
}
return val;
} Связывает заданное значение с заданным ключом; возвращает заданное значение.
Если заданный ключ существует, заменяет его значение заданным; порядок не изменяется (см. Порядок записей):
h = {foo: 0, bar: 1}
h[:foo] = 2 # => 2
h.store(:bar, 3) # => 3
h # => {:foo=>2, :bar=>3}
Если заданный ключ не существует, добавляет запись в конец (см. Порядок записей):
h = {foo: 0, bar: 1}
h[:baz] = 2 # => 2
h.store(:bat, 3) # => 3
h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
Исходный код
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_pair_yield_optimizable())
rb_hash_foreach(hash, any_p_i_fast, (VALUE)args);
else
rb_hash_foreach(hash, any_p_i, (VALUE)args);
}
return args[0];
} Возвращает true, если хотя бы один элемент удовлетворяет заданному критерию; в противном случае — false.
Если у self нет элементов, возвращает true, и аргумент или блок не используются.
Без аргументов и блока, возвращает true, если self не пустой; false, если пустой.
С аргументом object и без блока, возвращает true, если для любого ключа key выполняется h.assoc(key) == object:
h = {foo: 0, bar: 1, baz: 2}
h.any?([:bar, 1]) # => true
h.any?([:bar, 0]) # => false
h.any?([:baz, 1]) # => false
Без аргументов и с блоком, вызывает блок для каждой пары ключ-значение; возвращает true, если блок возвращает любое истинное значение, и false в противном случае:
h = {foo: 0, bar: 1, baz: 2}
h.any? {|key, value| value < 3 } # => true
h.any? {|key, value| value > 3 } # => false
См. также: Enumerable#any?
Исходный код
static VALUE
rb_hash_assoc(VALUE hash, VALUE key)
{
VALUE args[2];
if (RHASH_EMPTY_P(hash)) return Qnil;
if (RHASH_ST_TABLE_P(hash) && !RHASH_IDENTHASH_P(hash)) {
VALUE value = Qundef;
st_table assoctable = *RHASH_ST_TABLE(hash);
assoctable.type = &(struct st_hash_type){
.compare = assoc_cmp,
.hash = assoctable.type->hash,
};
VALUE arg = (VALUE)&(struct assoc_arg){
.tbl = &assoctable,
.key = (st_data_t)key,
};
if (RB_OBJ_FROZEN(hash)) {
value = assoc_lookup(arg);
}
else {
hash_iter_lev_inc(hash);
value = rb_ensure(assoc_lookup, arg, hash_foreach_ensure, hash);
}
hash_verify(hash);
if (!UNDEF_P(value)) return rb_assoc_new(key, value);
}
args[0] = key;
args[1] = Qnil;
rb_hash_foreach(hash, assoc_i, (VALUE)args);
return args[1];
} Если заданный ключ найден, возвращает массив из двух элементов содержащий ключ и его значение:
h = {foo: 0, bar: 1, baz: 2}
h.assoc(:bar) # => [:bar, 1]
Возвращает nil, если ключ key не найден.
Исходный код
VALUE
rb_hash_clear(VALUE hash)
{
rb_hash_modify_check(hash);
if (hash_iterating_p(hash)) {
rb_hash_foreach(hash, clear_i, 0);
}
else if (RHASH_AR_TABLE_P(hash)) {
ar_clear(hash);
}
else {
st_clear(RHASH_ST_TABLE(hash));
compact_after_delete(hash);
}
return hash;
} Удаляет все записи; возвращает self.
Исходный код
static VALUE
rb_hash_compact(VALUE hash)
{
VALUE result = rb_hash_dup(hash);
if (!RHASH_EMPTY_P(hash)) {
rb_hash_foreach(result, delete_if_nil, result);
compact_after_delete(result);
}
else if (rb_hash_compare_by_id_p(hash)) {
result = rb_hash_compare_by_id(result);
}
return result;
} Возвращает копию self без всех записей со значением nil:
h = {foo: 0, bar: nil, baz: 2, bat: nil}
h1 = h.compact
h1 # => {:foo=>0, :baz=>2}
Исходный код
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;
} Возвращает self без всех записей со значением nil (на месте):
h = {foo: 0, bar: nil, baz: 2, bat: nil}
h.compact! # => {:foo=>0, :baz=>2}
Возвращает nil, если записи не были удалены.
Исходный код
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);
if (hash_iterating_p(hash)) {
rb_raise(rb_eRuntimeError, "compare_by_identity during iteration");
}
if (RHASH_TABLE_EMPTY_P(hash)) {
// Fast path: There's nothing to rehash, so we don't need a `tmp` table.
// We're most likely an AR table, so this will need an allocation.
ar_force_convert_table(hash, __FILE__, __LINE__);
HASH_ASSERT(RHASH_ST_TABLE_P(hash));
RHASH_ST_TABLE(hash)->type = &identhash;
}
else {
// Slow path: Need to rehash the members of `self` into a new
// `tmp` table using the new `identhash` compare/hash functions.
tmp = hash_alloc(0);
hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash));
identtable = RHASH_ST_TABLE(tmp);
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
rb_hash_free(hash);
// We know for sure `identtable` is an st table,
// so we can skip `ar_force_convert_table` here.
RHASH_ST_TABLE_SET(hash, identtable);
RHASH_ST_CLEAR(tmp);
}
return hash;
} Устанавливает self использовать только идентичность при сравнении ключей; два ключа считаются одинаковыми только если они являются одним и тем же объектом; возвращает self.
По умолчанию, эти два объекта считаются одним и тем же ключом, поэтому s1 перезапишет s0:
s0 = 'x'
s1 = 'x'
h = {}
h.compare_by_identity? # => false
h[s0] = 0
h[s1] = 1
h # => {"x"=>1}
После вызова #compare_by_identity ключи считаются разными, и поэтому не перезаписывают друг друга:
h = {}
h.compare_by_identity # => {}
h.compare_by_identity? # => true
h[s0] = 0
h[s1] = 1
h # => {"x"=>0, "x"=>1}
Source
VALUE
rb_hash_compare_by_id_p(VALUE hash)
{
return RBOOL(RHASH_IDENTHASH_P(hash));
} Возвращает true если compare_by_identity был вызван, false иначе.
Source
static VALUE
rb_hash_default(int argc, VALUE *argv, VALUE hash)
{
VALUE ifnone;
rb_check_arity(argc, 0, 1);
ifnone = RHASH_IFNONE(hash);
if (FL_TEST(hash, RHASH_PROC_DEFAULT)) {
if (argc == 0) return Qnil;
return call_default_proc(ifnone, hash, argv[0]);
}
return ifnone;
} Возвращает значение по умолчанию для данного key. Возвращаемое значение будет определено либо процедурой по умолчанию, либо значением по умолчанию. См. Значения по умолчанию.
Без аргументов возвращает текущее значение по умолчанию:
h = {}
h.default # => nil
Если задан key, возвращает значение по умолчанию для key, независимо от того, существует ли этот ключ:
h = Hash.new { |hash, key| hash[key] = "No key #{key}"}
h[:foo] = "Hello"
h.default(:foo) # => "No key foo"
Source
static VALUE
rb_hash_set_default(VALUE hash, VALUE ifnone)
{
rb_hash_modify_check(hash);
SET_DEFAULT(hash, ifnone);
return ifnone;
} Устанавливает значение по умолчанию в value; возвращает value:
h = {}
h.default # => nil
h.default = false # => false
h.default # => false
Source
static VALUE
rb_hash_default_proc(VALUE hash)
{
if (FL_TEST(hash, RHASH_PROC_DEFAULT)) {
return RHASH_IFNONE(hash);
}
return Qnil;
} Возвращает процедуру по умолчанию для self (см. Значения по умолчанию):
h = {}
h.default_proc # => nil
h.default_proc = proc {|hash, key| "Default value for #{key}" }
h.default_proc.class # => Proc
Source
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;
} Устанавливает процедуру по умолчанию для self в proc (см. Значения по умолчанию):
h = {}
h.default_proc # => nil
h.default_proc = proc { |hash, key| "Default value for #{key}" }
h.default_proc.class # => Proc
h.default_proc = nil
h.default_proc # => nil
Source
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 (!UNDEF_P(val)) {
compact_after_delete(hash);
return val;
}
else {
if (rb_block_given_p()) {
return rb_yield(key);
}
else {
return Qnil;
}
}
} Удаляет запись для данного key и возвращает его связанное значение.
Если блок не задан и key найден, удаляет запись и возвращает связанное значение:
h = {foo: 0, bar: 1, baz: 2}
h.delete(:bar) # => 1
h # => {:foo=>0, :baz=>2}
Если блок не задан и key не найден, возвращает nil.
Если блок задан и key найден, игнорирует блок, удаляет запись и возвращает связанное значение:
h = {foo: 0, bar: 1, baz: 2}
h.delete(:baz) { |key| raise 'Will never happen'} # => 2
h # => {:foo=>0, :bar=>1}
Если блок задан и key не найден, вызывает блок и возвращает значение, возвращаемое блоком:
h = {foo: 0, bar: 1, baz: 2}
h.delete(:nosuch) { |key| "Key #{key} not found" } # => "Key nosuch not found"
h # => {:foo=>0, :bar=>1, :baz=>2}
Source
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);
compact_after_delete(hash);
}
return hash;
} Если задан блок, вызывает блок с каждой парой ключ-значение; удаляет каждую запись, для которой блок возвращает истинное значение; возвращает self:
h = {foo: 0, bar: 1, baz: 2}
h.delete_if {|key, value| value > 0 } # => {:foo=>0}
Если блок не задан, возвращает новый перечислитель:
h = {foo: 0, bar: 1, baz: 2}
e = h.delete_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:delete_if>
e.each { |key, value| value > 0 } # => {:foo=>0}
Source
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 и identifiers. Вложенные объекты могут быть экземплярами различных классов. См. Dig Methods.
Вложенные хеши:
h = {foo: {bar: {baz: 2}}}
h.dig(:foo) # => {:bar=>{:baz=>2}}
h.dig(:foo, :bar) # => {:baz=>2}
h.dig(:foo, :bar, :baz) # => 2
h.dig(:foo, :bar, :BAZ) # => nil
Вложенные хеши и массивы:
h = {foo: {bar: [:a, :b, :c]}}
h.dig(:foo, :bar, 2) # => :c
Этот метод будет использовать значения по умолчанию для ключей, которые отсутствуют:
h = {foo: {bar: [:a, :b, :c]}}
h.dig(:hello) # => nil
h.default_proc = -> (hash, _key) { hash }
h.dig(:hello, :world) # => h
h.dig(:hello, :world, :foo, :bar, 2) # => :c
Вызывает заданный блок с каждой парой ключ-значение; возвращает self:
h = {foo: 0, bar: 1, baz: 2}
h.each_pair {|key, value| puts "#{key}: #{value}"} # => {:foo=>0, :bar=>1, :baz=>2}
Вывод:
foo: 0 bar: 1 baz: 2
Возвращает новый Enumerator если блок не задан:
h = {foo: 0, bar: 1, baz: 2}
e = h.each_pair # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_pair>
h1 = e.each {|key, value| puts "#{key}: #{value}"}
h1 # => {:foo=>0, :bar=>1, :baz=>2}
Вывод:
foo: 0 bar: 1 baz: 2
Source
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;
} Вызывает заданный блок с каждым ключом; возвращает self:
h = {foo: 0, bar: 1, baz: 2}
h.each_key {|key| puts key } # => {:foo=>0, :bar=>1, :baz=>2}
Вывод:
foo bar baz
Возвращает новый Enumerator если блок не задан:
h = {foo: 0, bar: 1, baz: 2}
e = h.each_key # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_key>
h1 = e.each {|key| puts key }
h1 # => {:foo=>0, :bar=>1, :baz=>2}
Вывод:
foo bar baz
Source
static VALUE
rb_hash_each_pair(VALUE hash)
{
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
if (rb_block_pair_yield_optimizable())
rb_hash_foreach(hash, each_pair_i_fast, 0);
else
rb_hash_foreach(hash, each_pair_i, 0);
return hash;
} Вызывает заданный блок с каждой парой ключ-значение; возвращает self:
h = {foo: 0, bar: 1, baz: 2}
h.each_pair {|key, value| puts "#{key}: #{value}"} # => {:foo=>0, :bar=>1, :baz=>2}
Вывод:
foo: 0 bar: 1 baz: 2
Возвращает новый Enumerator если блок не задан:
h = {foo: 0, bar: 1, baz: 2}
e = h.each_pair # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_pair>
h1 = e.each {|key, value| puts "#{key}: #{value}"}
h1 # => {:foo=>0, :bar=>1, :baz=>2}
Вывод:
foo: 0 bar: 1 baz: 2
Source
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;
} Вызывает заданный блок с каждым значением; возвращает self:
h = {foo: 0, bar: 1, baz: 2}
h.each_value {|value| puts value } # => {:foo=>0, :bar=>1, :baz=>2}
Вывод:
0 1 2
Возвращает новый Enumerator если блок не задан:
h = {foo: 0, bar: 1, baz: 2}
e = h.each_value # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_value>
h1 = e.each {|value| puts value }
h1 # => {:foo=>0, :bar=>1, :baz=>2}
Вывод:
0 1 2
Source
VALUE
rb_hash_empty_p(VALUE hash)
{
return RBOOL(RHASH_EMPTY_P(hash));
} Возвращает true если нет записей в хеше, false в противном случае:
{}.empty? # => true
{foo: 0, bar: 1, baz: 2}.empty? # => false
Source
static VALUE
rb_hash_eql(VALUE hash1, VALUE hash2)
{
return hash_equal(hash1, hash2, TRUE);
} Возвращает true если истинны все следующие условия:
-
objectявляется объектомHash. -
hashиobjectимеют одинаковые ключи (независимо от порядка). -
Для каждого ключа
key,h[key].eql?(object[key]).
В противном случае, возвращает false.
h1 = {foo: 0, bar: 1, baz: 2}
h2 = {foo: 0, bar: 1, baz: 2}
h1.eql? h2 # => true
h3 = {baz: 2, bar: 1, foo: 0}
h1.eql? h3 # => true
Source
static VALUE
rb_hash_except(int argc, VALUE *argv, VALUE hash)
{
int i;
VALUE key, result;
result = hash_dup_with_compare_by_id(hash);
for (i = 0; i < argc; i++) {
key = argv[i];
rb_hash_delete(result, key);
}
compact_after_delete(result);
return result;
} Возвращает новый Hash без записей для заданных keys:
h = { a: 100, b: 200, c: 300 }
h.except(:a) #=> {:b=>200, :c=>300}
Любые заданные keys, которые не найдены, игнорируются.
Source
static VALUE
rb_hash_fetch_m(int argc, VALUE *argv, VALUE hash)
{
VALUE key;
st_data_t val;
long block_given;
rb_check_arity(argc, 1, 2);
key = argv[0];
block_given = rb_block_given_p();
if (block_given && argc == 2) {
rb_warn("block supersedes default value argument");
}
if (hash_stlike_lookup(hash, key, &val)) {
return (VALUE)val;
}
else {
if (block_given) {
return rb_yield(key);
}
else if (argc == 1) {
VALUE desc = rb_protect(rb_inspect, key, 0);
if (NIL_P(desc)) {
desc = rb_any_to_s(key);
}
desc = rb_str_ellipsize(desc, 65);
rb_key_err_raise(rb_sprintf("key not found: %"PRIsVALUE, desc), hash, key);
}
else {
return argv[1];
}
}
} Возвращает значение для заданного key, если оно найдено.
h = {foo: 0, bar: 1, baz: 2}
h.fetch(:bar) # => 1
Если key не найден и блок не был задан, возвращает default_value:
{}.fetch(:nosuch, :default) # => :default
Если key не найден и блок был задан, передает key в блок и возвращает значение, возвращаемое блоком:
{}.fetch(:nosuch) {|key| "No key #{key}"} # => "No key nosuch"
Вызывает исключение KeyError, если не был задан ни default_value, ни блок.
Обратите внимание, что этот метод не использует значения ни default, ни default_proc.
Source
static VALUE
rb_hash_fetch_values(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_fetch(hash, argv[i]));
}
return result;
} Возвращает новый Array содержащий значения, связанные с заданными ключами *keys:
h = {foo: 0, bar: 1, baz: 2}
h.fetch_values(:baz, :foo) # => [2, 0]
Возвращает новый пустой Array, если аргументы не заданы.
Когда задан блок, вызывает блок с каждым отсутствующим ключом, используя возвращаемое блоком значение как значение для этого ключа:
h = {foo: 0, bar: 1, baz: 2}
values = h.fetch_values(:bar, :foo, :bad, :bam) {|key| key.to_s}
values # => [1, 0, "bad", "bam"]
Когда блок не задан, вызывает исключение, если какой-либо заданный ключ не найден.
Source
static VALUE
rb_hash_flatten(int argc, VALUE *argv, VALUE hash)
{
VALUE ary;
rb_check_arity(argc, 0, 1);
if (argc) {
int level = NUM2INT(argv[0]);
if (level == 0) return rb_hash_to_a(hash);
ary = rb_ary_new_capa(RHASH_SIZE(hash) * 2);
rb_hash_foreach(hash, flatten_i, ary);
level--;
if (level > 0) {
VALUE ary_flatten_level = INT2FIX(level);
rb_funcallv(ary, id_flatten_bang, 1, &ary_flatten_level);
}
else if (level < 0) {
/* flatten recursively */
rb_funcallv(ary, id_flatten_bang, 0, 0);
}
}
else {
ary = rb_ary_new_capa(RHASH_SIZE(hash) * 2);
rb_hash_foreach(hash, flatten_i, ary);
}
return ary;
} Возвращает новый объект Array, представляющий собой одномерное сглаживание self.
По умолчанию, вложенные массивы не сглаживаются:
h = {foo: 0, bar: [:bat, 3], baz: 2}
h.flatten # => [:foo, 0, :bar, [:bat, 3], :baz, 2]
Принимает глубину рекурсивного сглаживания из аргумента Integer level:
h = {foo: 0, bar: [:bat, [:baz, [:bat, ]]]}
h.flatten(1) # => [:foo, 0, :bar, [:bat, [:baz, [:bat]]]]
h.flatten(2) # => [:foo, 0, :bar, :bat, [:baz, [:bat]]]
h.flatten(3) # => [:foo, 0, :bar, :bat, :baz, [:bat]]
h.flatten(4) # => [:foo, 0, :bar, :bat, :baz, :bat]
Когда level отрицателен, сглаживает все вложенные массивы:
h = {foo: 0, bar: [:bat, [:baz, [:bat, ]]]}
h.flatten(-1) # => [:foo, 0, :bar, :bat, :baz, :bat]
h.flatten(-2) # => [:foo, 0, :bar, :bat, :baz, :bat]
Когда level равен нулю, возвращает эквивалент to_a:
h = {foo: 0, bar: [:bat, 3], baz: 2}
h.flatten(0) # => [[:foo, 0], [:bar, [:bat, 3]], [:baz, 2]]
h.flatten(0) == h.to_a # => true
Возвращает true, если key является ключом в self, в противном случае false.
Source
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, если value является значением в self, в противном случае false.
Source
static VALUE
rb_hash_hash(VALUE hash)
{
st_index_t size = RHASH_SIZE(hash);
st_index_t hval = rb_hash_start(size);
hval = rb_hash_uint(hval, (st_index_t)rb_hash_hash);
if (size) {
rb_hash_foreach(hash, hash_i, (VALUE)&hval);
}
hval = rb_hash_end(hval);
return ST2FIX(hval);
} Возвращает Integer хэш-код для хеша.
Два объекта Hash имеют одинаковый хэш-код, если их содержимое одинаково (независимо от порядка):
h1 = {foo: 0, bar: 1, baz: 2}
h2 = {baz: 2, bar: 1, foo: 0}
h2.hash == h1.hash # => true
h2.eql? h1 # => true
Source
VALUE
rb_hash_has_key(VALUE hash, VALUE key)
{
return RBOOL(hash_stlike_lookup(hash, key, NULL));
} Возвращает true, если key является ключом в self, в противном случае false.
Source
static VALUE
rb_hash_inspect(VALUE hash)
{
if (RHASH_EMPTY_P(hash))
return rb_usascii_str_new2("{}");
return rb_exec_recursive(inspect_hash, hash, 0);
} Возвращает новый String содержащий записи хеша:
h = {foo: 0, bar: 1, baz: 2}
h.inspect # => "{foo: 0, bar: 1, baz: 2}"
Исходный код
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;
} Возвращает новый объект Hash с инвертированными парами ключ-значение:
h = {foo: 0, bar: 1, baz: 2}
h1 = h.invert
h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
Заменяет повторяющиеся новые ключи: (см. Порядок элементов):
h = {foo: 0, bar: 0, baz: 0}
h.invert # => {0=>:baz}
Исходный код
static 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;
} Вызывает блок для каждой пары ключ-значение; сохраняет элемент, если блок возвращает истинное значение; иначе удаляет элемент; возвращает self.
h = {foo: 0, bar: 1, baz: 2}
h.keep_if { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
Возвращает новый Enumerator, если блок не задан:
h = {foo: 0, bar: 1, baz: 2}
e = h.keep_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:keep_if>
e.each { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
Исходный код
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];
} Возвращает ключ для первого найденного элемента со заданным value (см. Порядок элементов):
h = {foo: 0, bar: 2, baz: 2}
h.key(0) # => :foo
h.key(2) # => :bar
Возвращает nil, если такой элемент не найден.
Возвращает true если key является ключом в self, иначе false.
Исходный код
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(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;
} Возвращает новый Array, содержащий все ключи в self:
h = {foo: 0, bar: 1, baz: 2}
h.keys # => [:foo, :bar, :baz]
Возвращает количество элементов в self:
{foo: 0, bar: 1, baz: 2}.length # => 3
Возвращает true если key является ключом в self, иначе false.
Исходный код
static VALUE
rb_hash_merge(int argc, VALUE *argv, VALUE self)
{
return rb_hash_update(argc, argv, copy_compare_by_id(rb_hash_dup(self), self));
} Возвращает новый Hash, образованный слиянием каждого из other_hashes в копию self.
Каждый аргумент в other_hashes должен быть Hash.
С аргументами и без блока:
-
Возвращает новый
Hashобъект, образованный слиянием каждого последующегоHashвother_hashesвself. -
Каждый новый элемент добавляется в конец.
-
Значение каждого элемента с дублирующимся ключом перезаписывает предыдущее значение.
Пример:
h = {foo: 0, bar: 1, baz: 2}
h1 = {bat: 3, bar: 4}
h2 = {bam: 5, bat:6}
h.merge(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5}
С аргументами и блоком:
-
Возвращает новый
Hashобъект, являющийся результатом слиянияselfи каждого заданного хэша. -
Заданные хэши сливаются слева направо.
-
Каждый новый элемент добавляется в конец.
-
Для каждого дублирующегося ключа:
-
Вызывает блок с ключом и старыми и новыми значениями.
-
Возвращаемое значение блока становится новым значением для элемента.
-
Пример:
h = {foo: 0, bar: 1, baz: 2}
h1 = {bat: 3, bar: 4}
h2 = {bam: 5, bat:6}
h3 = h.merge(h1, h2) { |key, old_value, new_value| old_value + new_value }
h3 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5}
Без аргументов:
-
Возвращает копию
self. -
Блок, если задан, игнорируется.
Пример:
h = {foo: 0, bar: 1, baz: 2}
h.merge # => {:foo=>0, :bar=>1, :baz=>2}
h1 = h.merge { |key, old_value, new_value| raise 'Cannot happen' }
h1 # => {:foo=>0, :bar=>1, :baz=>2}
Сливает каждый из other_hashes в self; возвращает self.
Каждый аргумент в other_hashes должен быть Hash.
С аргументами и без блока:
-
Возвращает
self, после слияния заданных хэшей в него. -
Заданные хэши сливаются слева направо.
-
Каждый новый элемент добавляется в конец.
-
Значение каждого элемента с дублирующимся ключом перезаписывает предыдущее значение.
Пример:
h = {foo: 0, bar: 1, baz: 2}
h1 = {bat: 3, bar: 4}
h2 = {bam: 5, bat:6}
h.merge!(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5}
С аргументами и блоком:
-
Возвращает
self, после слияния заданных хэшей. -
Заданные хэши сливаются слева направо.
-
Каждый новый элемент добавляется в конец.
-
Для каждого дублирующегося ключа:
-
Вызывает блок с ключом и старыми и новыми значениями.
-
Возвращаемое значение блока становится новым значением для элемента.
-
Пример:
h = {foo: 0, bar: 1, baz: 2}
h1 = {bat: 3, bar: 4}
h2 = {bam: 5, bat:6}
h3 = h.merge!(h1, h2) { |key, old_value, new_value| old_value + new_value }
h3 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5}
Без аргументов:
-
Возвращает
self, без изменений. -
Блок, если задан, игнорируется.
Пример:
h = {foo: 0, bar: 1, baz: 2}
h.merge # => {:foo=>0, :bar=>1, :baz=>2}
h1 = h.merge! { |key, old_value, new_value| raise 'Cannot happen' }
h1 # => {:foo=>0, :bar=>1, :baz=>2}
Исходный код
static VALUE
rb_hash_rassoc(VALUE hash, VALUE obj)
{
VALUE args[2];
args[0] = obj;
args[1] = Qnil;
rb_hash_foreach(hash, rassoc_i, (VALUE)args);
return args[1];
} Возвращает новый 2-элементный Array, состоящий из ключа и значения первого найденного элемента, значение которого равно == значению (см. Порядок элементов):
h = {foo: 0, bar: 1, baz: 1}
h.rassoc(1) # => [:bar, 1]
Возвращает nil если такого значения не найдено.
Исходный код
VALUE
rb_hash_rehash(VALUE hash)
{
VALUE tmp;
st_table *tbl;
if (hash_iterating_p(hash)) {
rb_raise(rb_eRuntimeError, "rehash during iteration");
}
rb_hash_modify_check(hash);
if (RHASH_AR_TABLE_P(hash)) {
tmp = hash_alloc(0);
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
hash_ar_free_and_clear_table(hash);
ar_copy(hash, tmp);
}
else if (RHASH_ST_TABLE_P(hash)) {
st_table *old_tab = RHASH_ST_TABLE(hash);
tmp = hash_alloc(0);
hash_st_table_init(tmp, old_tab->type, old_tab->num_entries);
tbl = RHASH_ST_TABLE(tmp);
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
hash_st_free(hash);
RHASH_ST_TABLE_SET(hash, tbl);
RHASH_ST_CLEAR(tmp);
}
hash_verify(hash);
return hash;
} Перестраивает таблицу хэшей, пересчитывая индекс хэша для каждого ключа; возвращает self.
Таблица хэшей становится недействительной, если значение хэша ключа изменилось после создания элемента. См. Изменение активного ключа хэша.
Исходный код
static VALUE
rb_hash_reject(VALUE hash)
{
VALUE result;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
result = hash_dup_with_compare_by_id(hash);
if (!RHASH_EMPTY_P(hash)) {
rb_hash_foreach(result, delete_if_i, result);
compact_after_delete(result);
}
return result;
} Возвращает новый объект Hash, чьи записи — это все те записи из self, для которых блок возвращает false или nil;
h = {foo: 0, bar: 1, baz: 2}
h1 = h.reject {|key, value| key.start_with?('b') }
h1 # => {:foo=>0}
Возвращает новый Enumerator, если блок не задан:
h = {foo: 0, bar: 1, baz: 2}
e = h.reject # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject>
h1 = e.each {|key, value| key.start_with?('b') }
h1 # => {:foo=>0}
Исходный код
static VALUE
rb_hash_reject_bang(VALUE hash)
{
st_index_t n;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify(hash);
n = RHASH_SIZE(hash);
if (!n) return Qnil;
rb_hash_foreach(hash, delete_if_i, hash);
if (n == RHASH_SIZE(hash)) return Qnil;
return hash;
} Возвращает self, чьи оставшиеся записи — это те записи, для которых блок возвращает false или nil:
h = {foo: 0, bar: 1, baz: 2}
h.reject! {|key, value| value < 2 } # => {:baz=>2}
Возвращает nil, если ни одна запись не была удалена.
Возвращает новый Enumerator, если блок не задан:
h = {foo: 0, bar: 1, baz: 2}
e = h.reject! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject!>
e.each {|key, value| key.start_with?('b') } # => {:foo=>0}
Заменяет все содержимое self содержимым other_hash; возвращает self:
h = {foo: 0, bar: 1, baz: 2}
h.replace({bat: 3, bam: 4}) # => {:bat=>3, :bam=>4}
Исходный код
static VALUE
rb_hash_select(VALUE hash)
{
VALUE result;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
result = hash_dup_with_compare_by_id(hash);
if (!RHASH_EMPTY_P(hash)) {
rb_hash_foreach(result, keep_if_i, result);
compact_after_delete(result);
}
return result;
} Возвращает новый объект Hash, чьи записи — это те записи, для которых блок возвращает истинное значение:
h = {foo: 0, bar: 1, baz: 2}
h.select {|key, value| value < 2 } # => {:foo=>0, :bar=>1}
Возвращает новый Enumerator, если блок не задан:
h = {foo: 0, bar: 1, baz: 2}
e = h.select # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select>
e.each {|key, value| value < 2 } # => {:foo=>0, :bar=>1}
Исходный код
static VALUE
rb_hash_select_bang(VALUE hash)
{
st_index_t n;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify_check(hash);
n = RHASH_SIZE(hash);
if (!n) return Qnil;
rb_hash_foreach(hash, keep_if_i, hash);
if (n == RHASH_SIZE(hash)) return Qnil;
return hash;
} Возвращает self, чьи записи — это те записи, для которых блок возвращает истинное значение:
h = {foo: 0, bar: 1, baz: 2}
h.select! {|key, value| value < 2 } => {:foo=>0, :bar=>1} Возвращает nil если ни одна запись не была удалена.
Возвращает новый Enumerator, если блок не задан:
h = {foo: 0, bar: 1, baz: 2}
e = h.select! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select!>
e.each { |key, value| value < 2 } # => {:foo=>0, :bar=>1}
Исходный код
static VALUE
rb_hash_shift(VALUE hash)
{
struct shift_var var;
rb_hash_modify_check(hash);
if (RHASH_AR_TABLE_P(hash)) {
var.key = Qundef;
if (!hash_iterating_p(hash)) {
if (ar_shift(hash, &var.key, &var.val)) {
return rb_assoc_new(var.key, var.val);
}
}
else {
rb_hash_foreach(hash, shift_i_safe, (VALUE)&var);
if (!UNDEF_P(var.key)) {
rb_hash_delete_entry(hash, var.key);
return rb_assoc_new(var.key, var.val);
}
}
}
if (RHASH_ST_TABLE_P(hash)) {
var.key = Qundef;
if (!hash_iterating_p(hash)) {
if (st_shift(RHASH_ST_TABLE(hash), &var.key, &var.val)) {
return rb_assoc_new(var.key, var.val);
}
}
else {
rb_hash_foreach(hash, shift_i_safe, (VALUE)&var);
if (!UNDEF_P(var.key)) {
rb_hash_delete_entry(hash, var.key);
return rb_assoc_new(var.key, var.val);
}
}
}
return Qnil;
} Удаляет первую запись хэша (см. Порядок записей); возвращает 2-элементный массив Array, содержащий удалённый ключ и значение:
h = {foo: 0, bar: 1, baz: 2}
h.shift # => [:foo, 0]
h # => {:bar=>1, :baz=>2}
Возвращает null, если хэш пуст.
Исходный код
VALUE
rb_hash_size(VALUE hash)
{
return INT2FIX(RHASH_SIZE(hash));
} Возвращает количество записей в self:
{foo: 0, bar: 1, baz: 2}.length # => 3
Исходный код
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 copy_compare_by_id(rb_hash_new(), hash);
}
result = copy_compare_by_id(rb_hash_new_with_size(argc), hash);
for (i = 0; i < argc; i++) {
key = argv[i];
value = rb_hash_lookup2(hash, key, Qundef);
if (!UNDEF_P(value))
rb_hash_aset(result, key, value);
}
return result;
} Возвращает новый объект Hash, содержащий записи для заданных keys:
h = {foo: 0, bar: 1, baz: 2}
h.slice(:baz, :foo) # => {:baz=>2, :foo=>0}
Любые заданные keys которые не найдены, игнорируются.
Связывает данный value с данным key; возвращает value.
Если данный key существует, заменяет его значение на заданное value; порядок не затрагивается (см. Порядок записей):
h = {foo: 0, bar: 1}
h[:foo] = 2 # => 2
h.store(:bar, 3) # => 3
h # => {:foo=>2, :bar=>3}
Если key не существует, добавляет key и value; новая запись расположена последней в порядке (см. Порядок записей):
h = {foo: 0, bar: 1}
h[:baz] = 2 # => 2
h.store(:bat, 3) # => 3
h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
Исходный код
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;
} Возвращает новый массив Array из 2-элементных массивов Array; каждый вложенный массив Array содержит пару ключ-значение из self:
h = {foo: 0, bar: 1, baz: 2}
h.to_a # => [[:foo, 0], [:bar, 1], [:baz, 2]]
Исходный код
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;
} Для экземпляра Hash, возвращает self.
Для подкласса Hash, возвращает новый Hash, содержащий содержимое self.
Когда задан блок, возвращает новый объект Hash, чьё содержимое основано на блоке; блок должен возвращать объект массива Array из 2 элементов, определяющий пару ключ-значение, которая будет включена в возвращённый массив:
h = {foo: 0, bar: 1, baz: 2}
h1 = h.to_h {|key, value| [value, key] }
h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
Исходный код
static VALUE
rb_hash_to_hash(VALUE hash)
{
return hash;
} Возвращает self.
Исходный код
static VALUE
rb_hash_to_proc(VALUE hash)
{
return rb_func_lambda_new(hash_proc_call, hash, 1, 1);
} Возвращает объект Proc, который сопоставляет ключ со значением:
h = {foo: 0, bar: 1, baz: 2}
proc = h.to_proc
proc.class # => Proc
proc.call(:foo) # => 0
proc.call(:bar) # => 1
proc.call(:nosuch) # => nil
Исходный код
static VALUE
rb_hash_transform_keys(int argc, VALUE *argv, VALUE hash)
{
VALUE result;
struct transform_keys_args transarg = {0};
argc = rb_check_arity(argc, 0, 1);
if (argc > 0) {
transarg.trans = to_hash(argv[0]);
transarg.block_given = rb_block_given_p();
}
else {
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
}
result = rb_hash_new();
if (!RHASH_EMPTY_P(hash)) {
if (transarg.trans) {
transarg.result = result;
rb_hash_foreach(hash, transform_keys_hash_i, (VALUE)&transarg);
}
else {
rb_hash_foreach(hash, transform_keys_i, result);
}
}
return result;
} Возвращает новый объект Hash; каждая запись имеет:
-
Ключ, заданный блоком.
-
Значение из
self.
Можно указать необязательный аргумент хеша для отображения ключей на новые ключи. Любой ключ, не заданный, будет отображён с помощью предоставленного блока или останется прежним, если блок не указан.
Преобразование ключей:
h = {foo: 0, bar: 1, baz: 2}
h1 = h.transform_keys {|key| key.to_s }
h1 # => {"foo"=>0, "bar"=>1, "baz"=>2}
h.transform_keys(foo: :bar, bar: :foo)
#=> {bar: 0, foo: 1, baz: 2}
h.transform_keys(foo: :hello, &:to_s)
#=> {:hello=>0, "bar"=>1, "baz"=>2}
Перезаписывает значения для дублирующих ключей:
h = {foo: 0, bar: 1, baz: 2}
h1 = h.transform_keys {|key| :bat }
h1 # => {:bat=>2}
Возвращает новый Enumerator, если блок не указан:
h = {foo: 0, bar: 1, baz: 2}
e = h.transform_keys # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_keys>
h1 = e.each { |key| key.to_s }
h1 # => {"foo"=>0, "bar"=>1, "baz"=>2}
Исходный код
static VALUE
rb_hash_transform_keys_bang(int argc, VALUE *argv, VALUE hash)
{
VALUE trans = 0;
int block_given = 0;
argc = rb_check_arity(argc, 0, 1);
if (argc > 0) {
trans = to_hash(argv[0]);
block_given = rb_block_given_p();
}
else {
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
}
rb_hash_modify_check(hash);
if (!RHASH_TABLE_EMPTY_P(hash)) {
long i;
VALUE new_keys = hash_alloc(0);
VALUE pairs = rb_ary_hidden_new(RHASH_SIZE(hash) * 2);
rb_hash_foreach(hash, flatten_i, pairs);
for (i = 0; i < RARRAY_LEN(pairs); i += 2) {
VALUE key = RARRAY_AREF(pairs, i), new_key, val;
if (!trans) {
new_key = rb_yield(key);
}
else if (!UNDEF_P(new_key = rb_hash_lookup2(trans, key, Qundef))) {
/* use the transformed key */
}
else if (block_given) {
new_key = rb_yield(key);
}
else {
new_key = key;
}
val = RARRAY_AREF(pairs, i+1);
if (!hash_stlike_lookup(new_keys, key, NULL)) {
rb_hash_stlike_delete(hash, &key, NULL);
}
rb_hash_aset(hash, new_key, val);
rb_hash_aset(new_keys, new_key, Qnil);
}
rb_ary_clear(pairs);
rb_hash_clear(new_keys);
}
compact_after_delete(hash);
return hash;
} То же самое, что и Hash#transform_keys, но изменяет получатель на месте вместо возвращения нового хеша.
Исходный код
static VALUE
rb_hash_transform_values(VALUE hash)
{
VALUE result;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
result = hash_dup_with_compare_by_id(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);
compact_after_delete(result);
}
return result;
} Возвращает новый объект Hash; каждая запись имеет:
-
Ключ из
self. -
Значение, заданное блоком.
Преобразование значений:
h = {foo: 0, bar: 1, baz: 2}
h1 = h.transform_values {|value| value * 100}
h1 # => {:foo=>0, :bar=>100, :baz=>200}
Возвращает новый Enumerator, если блок не указан:
h = {foo: 0, bar: 1, baz: 2}
e = h.transform_values # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_values>
h1 = e.each { |value| value * 100}
h1 # => {:foo=>0, :bar=>100, :baz=>200}
Исходный код
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;
} Возвращает self, у которого ключи неизменны, а значения определяются заданным блоком.
h = {foo: 0, bar: 1, baz: 2}
h.transform_values! {|value| value * 100} # => {:foo=>0, :bar=>100, :baz=>200}
Возвращает новый Enumerator если блок не указан:
h = {foo: 0, bar: 1, baz: 2}
e = h.transform_values! # => #<Enumerator: {:foo=>0, :bar=>100, :baz=>200}:transform_values!>
h1 = e.each {|value| value * 100}
h1 # => {:foo=>0, :bar=>100, :baz=>200}
Возвращает true если value — значение в self, в противном случае 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(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(values, ptr, {
size = st_values(table, ptr, size);
});
}
rb_ary_set_len(values, size);
}
else {
rb_hash_foreach(hash, values_i, values);
}
return values;
} Возвращает новый Array, содержащий все значения в self:
h = {foo: 0, bar: 1, baz: 2}
h.values # => [0, 1, 2]
Исходный код
static 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;
} Возвращает новый Array, содержащий значения для заданных keys:
h = {foo: 0, bar: 1, baz: 2}
h.values_at(:baz, :foo) # => [2, 0]
Значения по умолчанию возвращаются для любых ключей, которые не найдены:
h.values_at(:hello, :foo) # => [nil, 0]
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.