mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
hash.c: Add Hash#transform_keys and Hash#transform_keys!
* hash.c (transform_keys_i, rb_hash_transform_keys): Add Hash#transform_keys. [Feature #13583] [ruby-core:81290] * hash.c (rb_hash_transform_keys_bang): Add Hash#transform_keys!. [Feature #13583] [ruby-core:81290] * test/ruby/test_hash.rb: Add tests for above changes. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59328 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
0b396d5880
commit
1405111722
2 changed files with 102 additions and 0 deletions
74
hash.c
74
hash.c
|
@ -1824,6 +1824,78 @@ rb_hash_each_pair(VALUE hash)
|
|||
return hash;
|
||||
}
|
||||
|
||||
static int
|
||||
transform_keys_i(VALUE key, VALUE value, VALUE result)
|
||||
{
|
||||
VALUE new_key = rb_yield(key);
|
||||
rb_hash_aset(result, new_key, value);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* hsh.transform_keys {|key| block } -> new_hash
|
||||
* hsh.transform_keys -> an_enumerator
|
||||
*
|
||||
* Returns a new hash with the results of running the block once for
|
||||
* every key.
|
||||
* This method does not change the values.
|
||||
*
|
||||
* 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 }
|
||||
*
|
||||
* If no block is given, an enumerator is returned instead.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* hsh.transform_keys! {|value| block } -> hsh
|
||||
* hsh.transform_keys! -> an_enumerator
|
||||
*
|
||||
* Invokes the given block once for each key in <i>hsh</i>, replacing it
|
||||
* with the new key returned by the block, and then returns <i>hsh</i>.
|
||||
* This method does not change the values.
|
||||
*
|
||||
* 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 }
|
||||
*
|
||||
* If no block is given, an enumerator is returned instead.
|
||||
*/
|
||||
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(hash)->ntbl) {
|
||||
long i;
|
||||
VALUE keys = rb_hash_keys(hash);
|
||||
for (i = 0; i < RARRAY_LEN(keys); ++i) {
|
||||
VALUE new_key = rb_yield(RARRAY_AREF(keys, i));
|
||||
rb_hash_aset(hash, new_key, rb_hash_delete(hash, RARRAY_AREF(keys, i)));
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static int
|
||||
transform_values_i(VALUE key, VALUE value, VALUE result)
|
||||
{
|
||||
|
@ -4507,6 +4579,8 @@ Init_Hash(void)
|
|||
rb_define_method(rb_cHash, "each_pair", rb_hash_each_pair, 0);
|
||||
rb_define_method(rb_cHash, "each", rb_hash_each_pair, 0);
|
||||
|
||||
rb_define_method(rb_cHash, "transform_keys", rb_hash_transform_keys, 0);
|
||||
rb_define_method(rb_cHash, "transform_keys!", rb_hash_transform_keys_bang, 0);
|
||||
rb_define_method(rb_cHash, "transform_values", rb_hash_transform_values, 0);
|
||||
rb_define_method(rb_cHash, "transform_values!", rb_hash_transform_values_bang, 0);
|
||||
|
||||
|
|
|
@ -1530,6 +1530,34 @@ class TestHash < Test::Unit::TestCase
|
|||
assert_equal([10, 20, 30], [1, 2, 3].map(&h))
|
||||
end
|
||||
|
||||
def test_transform_keys
|
||||
x = @cls[a: 1, b: 2, c: 3]
|
||||
y = x.transform_keys {|k| :"#{k}!" }
|
||||
assert_equal({a: 1, b: 2, c: 3}, x)
|
||||
assert_equal({a!: 1, b!: 2, c!: 3}, y)
|
||||
|
||||
enum = x.transform_keys
|
||||
assert_equal(x.size, enum.size)
|
||||
assert_instance_of(Enumerator, enum)
|
||||
|
||||
y = x.transform_keys.with_index {|k, i| "#{k}.#{i}" }
|
||||
assert_equal(%w(a.0 b.1 c.2), y.keys)
|
||||
end
|
||||
|
||||
def test_transform_keys_bang
|
||||
x = @cls[a: 1, b: 2, c: 3]
|
||||
y = x.transform_keys! {|k| :"#{k}!" }
|
||||
assert_equal({a!: 1, b!: 2, c!: 3}, x)
|
||||
assert_same(x, y)
|
||||
|
||||
enum = x.transform_keys!
|
||||
assert_equal(x.size, enum.size)
|
||||
assert_instance_of(Enumerator, enum)
|
||||
|
||||
x.transform_keys!.with_index {|k, i| "#{k}.#{i}" }
|
||||
assert_equal(%w(a!.0 b!.1 c!.2), x.keys)
|
||||
end
|
||||
|
||||
def test_transform_values
|
||||
x = @cls[a: 1, b: 2, c: 3]
|
||||
y = x.transform_values {|v| v ** 2 }
|
||||
|
|
Loading…
Reference in a new issue