Project

General

Profile

Feature #13583

Adding `Hash#transform_keys` method

Added by graywolf (Gray Wolf) about 1 year ago. Updated 8 months ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:81290]

Description

In 2.4, new useful method Hash#transform_values was added. I would like to propose also adding matching method Hash#transform_keys.

{a: 1, b: 2}.transform_keys { |k| k.to_s }
=> {"a"=>1, "b"=>2}

What needs to be considered is what to do in case of two keys mapping to the same new key

{ a: 1, b: 2 }.transform_keys {|_| :same_key } # what should happen?

I think using Hash[] as model behaviour is a good idea.

Hash[{ a: 1, b: 2 }.map { |key, value| [:s, value] }]
=> {:s=>2}

it's also how Hash#transform_keys works in rails (afaict).

This is a follow up feature request to #9970, which seems to be stalled. If the behaviour can be agreed upon, I can try putting together a patch (if no one else wants to step up).

Associated revisions

Revision 14051117
Added by mrkn (Kenta Murata) about 1 year ago

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]

  • hash.c (rb_hash_transform_keys_bang): Add Hash#transform_keys!.
    [Feature #13583]

  • 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

Revision 59328
Added by mrkn (Kenta Murata) about 1 year ago

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]

  • hash.c (rb_hash_transform_keys_bang): Add Hash#transform_keys!.
    [Feature #13583]

  • test/ruby/test_hash.rb: Add tests for above changes.

Revision 59328
Added by mrkn (Kenta Murata) about 1 year ago

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]

  • hash.c (rb_hash_transform_keys_bang): Add Hash#transform_keys!.
    [Feature #13583]

  • test/ruby/test_hash.rb: Add tests for above changes.

Revision ae1c9f13
Added by znz (Kazuhiro NISHIYAMA) about 1 year ago

NEWS: Add Hash#transform_keys and Hash#transform_keys!

[Feature #13583] [ci skip]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59369 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Revision 59369
Added by znz (Kazuhiro NISHIYAMA) about 1 year ago

NEWS: Add Hash#transform_keys and Hash#transform_keys!

[Feature #13583] [ci skip]

Revision 59369
Added by kazu about 1 year ago

NEWS: Add Hash#transform_keys and Hash#transform_keys!

[Feature #13583] [ci skip]

History

#1 Updated by graywolf (Gray Wolf) about 1 year ago

  • Description updated (diff)

#2 Updated by graywolf (Gray Wolf) about 1 year ago

  • Description updated (diff)

#3 [ruby-core:81298] Updated by shyouhei (Shyouhei Urabe) about 1 year ago

Thank you for issuing this. I see there is an obvious needs for this transformation (stringify_keys) so I'm :+1: to the feature.

Let's have a concrete definition of this requested method:

  • Its name is Hash#transform_keys.
  • It returns a newly created Hash instance.
  • It has zero arity.
  • It yields,
    • with only one block parameter (which is a key of the original hash),
    • the evaluated value is the new key for the entry.
  • When the new key conflicts, later entry silently discards former entry (see the description of this issue).

Is it okey? Am I missing something? Do people have any opinion?

#4 [ruby-core:81304] Updated by graywolf (Gray Wolf) about 1 year ago

I don't think you missed anything, except I would just point out to also add Hash#transform_keys!. I don't know if it's worth mentioning or just kinda automatically assumed.

#5 [ruby-core:81314] Updated by shevegen (Robert A. Heiler) about 1 year ago

I think the names are good, both #transform_keys and #transform_values.

Seem quite clear to me from the names.

On the linked older issue (-3 years), the names were different,
Hash#map_keys and Hash#map_values. Matz said that the names may
be confusing. Perhaps #transform_keys and #transform_values
are better names. (I have not checked if the proposal is the
very same; shyouhei provided a very specific definition here,
including behaviour such as arity and yield-situations, which
I think the other proposal did not have). Guess matz will have
a look.

graywolf, could you perhaps show some example documentation for
the two methods?

#6 [ruby-core:82044] Updated by matz (Yukihiro Matsumoto) about 1 year ago

Looks good to me.

Matz.

#7 Updated by mrkn (Kenta Murata) about 1 year ago

  • Status changed from Open to Closed

Applied in changeset trunk|r59328.


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]

  • hash.c (rb_hash_transform_keys_bang): Add Hash#transform_keys!.
    [Feature #13583]

  • test/ruby/test_hash.rb: Add tests for above changes.

#8 [ruby-core:84170] Updated by marcandre (Marc-Andre Lafortune) 8 months ago

  • Assignee set to matz (Yukihiro Matsumoto)
  • Status changed from Closed to Open

I'm not sure I like the current behavior of transform_keys!.

Two possibilities: transform_keys! is each_key { delete(old_key), set(new_key) } (as is currently) or replace(transform_keys) (I think I prefer this).

Matz, could you confirm what behavior you want?

Current:

h = {1 => :hello, 2 => 'world'}
h.transform_keys(&:succ) # => {2 => :hello, 3 => 'world'}
h.transform_keys!(&:succ) # => {3 => :hello}

With using replace, we'd get the same results.

The current behavior allows partial updates though:

h = {1 => :hello, 2 => :world}
h.transform_keys! { |k| k == 1 ? :one : break }
h # => {2 => world, :one => :hello}

With the replace version, h would be unchanged (or else we'd have to write an ensure to do the partial update)

#9 [ruby-core:84172] Updated by marcandre (Marc-Andre Lafortune) 8 months ago

  • Status changed from Open to Closed

Nevermind, I just remembered that ActiveSupport also defines transform_keys!, so best match its behavior.

Also available in: Atom PDF