Project

General

Profile

Feature #8499

Importing Hash#slice, Hash#slice!, Hash#except, and Hash#except! from ActiveSupport

Added by Kenta Murata over 3 years ago. Updated about 1 year ago.

Status:
Assigned
Priority:
Normal
[ruby-core:55330]

Description

According to my experiences, the following two idioms often appeare in application codes.

  1. hash = other_hash.select { |k, | [:key1, :key2, :key3].include? k }
  2. hash = other_hash.reject { |k, | [:key1, :key2, :key3].include? k }

On Rails, they can be written in the following forms by using ActiveSupport's features.

  1. hash = other_hash.slice(:key1, :key2, :key3)
  2. hash = other_hash.except(:key1, :key2, :key3)

I think the latter forms are shorter and more readable than the former ones.

So I propose to import the following methods from ActiveSupport:

  • Hash#slice
  • Hash#slice!
  • Hash#except
  • Hash#except!

patch.diff View - built-in Hash#slice, Hash#slice!, Hash#except, and Hash#except! (4.05 KB) Masaki Matsushita, 07/26/2013 10:58 PM

patch2.diff View (4.07 KB) Masaki Matsushita, 07/29/2013 12:24 PM


Related issues

Related to Ruby trunk - Feature #9108: Hash sub-selections Open
Related to Ruby trunk - Feature #12461: Hash & keys to make subset. Rejected

History

#2 [ruby-core:55332] Updated by Zachary Scott over 3 years ago

Hello,

On Thu, Jun 6, 2013 at 4:12 PM, mrkn (Kenta Murata) muraken@gmail.com wrote:

On Rails, they can be written in the following forms by using ActiveSupport's features.

  1. hash = other_hash.slice(:key1, :key2, :key3)
  2. hash = other_hash.reject(:key1, :key2, :key3}

Do you mean "other_hash.except(...)"? There is already Hash#reject

#3 [ruby-core:55333] Updated by Nobuyoshi Nakada over 3 years ago

  • Description updated (diff)

#4 [ruby-core:55334] Updated by Kenta Murata over 3 years ago

zzak (Zachary Scott) wrote:

Hello,

On Thu, Jun 6, 2013 at 4:12 PM, mrkn (Kenta Murata) muraken@gmail.com wrote:

On Rails, they can be written in the following forms by using ActiveSupport's features.

  1. hash = other_hash.slice(:key1, :key2, :key3)
  2. hash = other_hash.reject(:key1, :key2, :key3}

Do you mean "other_hash.except(...)"? There is already Hash#reject

Yes, It's my mistake!

How can I edit the issue description?

#5 [ruby-core:55335] Updated by Kenta Murata over 3 years ago

  • Description updated (diff)

I could fix the description.

#6 [ruby-core:55336] Updated by Nobuyoshi Nakada over 3 years ago

Or enhance the existing methods?

#7 [ruby-core:55338] Updated by Kenta Murata over 3 years ago

nobu (Nobuyoshi Nakada) wrote:

Or enhance the existing methods?

I think Hash#[] with the multiple arguments can be an alternative of Hash#slice.

#9 [ruby-core:55342] Updated by Nobuyoshi Nakada over 3 years ago

mrkn (Kenta Murata) wrote:

I think Hash#[] with the multiple arguments can be an alternative of Hash#slice.

Hash#[] should return the values, not the pairs.

#11 [ruby-core:55344] Updated by Ilya Vorontsov over 3 years ago

mrkn (Kenta Murata) wrote:

nobu (Nobuyoshi Nakada) wrote:

Or enhance the existing methods?

I think Hash#[] with the multiple arguments can be an alternative of Hash#slice.

There was a proposal (can't find it) to make indexing by multiple arguments to work as nested hashes so that hsh[:a,:b,:c] works as (hsh[:a] && hsh[:a][:b] && hsh[:a][:b][:c]). Your proposal automatically blocks this proposal.

#12 [ruby-core:55346] Updated by Kenta Murata over 3 years ago

prijutme4ty (Ilya Vorontsov) wrote:

mrkn (Kenta Murata) wrote:

nobu (Nobuyoshi Nakada) wrote:

Or enhance the existing methods?

I think Hash#[] with the multiple arguments can be an alternative of Hash#slice.

There was a proposal (can't find it) to make indexing by multiple arguments to work as nested hashes so that hsh[:a,:b,:c] works as (hsh[:a] && hsh[:a][:b] && hsh[:a][:b][:c]). Your proposal automatically blocks this proposal.

My proposal primaliry consists of Hash#slice, Hash#except, and bang versions of them.
Hash#[] is optional.

#13 [ruby-core:55345] Updated by Clay Trump over 3 years ago

Yay, +1 for slice & except

BTW, makes no sense to me if h[:foo, :bar] returns keys and values in a
hash while h[:foo] returns a value.


<lay trum/>

#15 [ruby-core:55351] Updated by Kenta Murata over 3 years ago

On Fri, Jun 7, 2013 at 1:50 AM, Zachary Scott zachary@zacharyscott.net wrote:

Please update description if the proposal has changed (ie: Hash#[])

I mentioned Hash#[] as the reply to nobu's comment #6.
It has not changed my proposal.
My proposal only consists of slice, slice!, except, and except!.

--
Kenta Murata
OpenPGP FP = 1D69 ADDE 081C 9CC2 2E54 98C1 CEFE 8AFB 6081 B062

#16 [ruby-core:55352] Updated by Nobuyoshi Nakada over 3 years ago

I meant Hash#select and Hash#reject by "the existing methods".

i.e.:

hash = other_hash.select(:key1, :key2, :key3)
hash = other_hash.reject(:key1, :key2, :key3)

But Hash#slice and Hash#except seems fine.

#17 [ruby-core:56205] Updated by Masaki Matsushita over 3 years ago

How about this implementation?

#18 [ruby-core:56220] Updated by Yukihiro Matsumoto over 3 years ago

The slice method (Array#slice) retrieve "a slice of elements" from an Array.
Considering that, slice is not a good name for the behavior.

So, I prefer Nobu's idea in comment #16

hash = other_hash.select(:key1, :key2, :key3)
hash = other_hash.reject(:key1, :key2, :key3)

Matz

#19 [ruby-core:56221] Updated by Kazuhiro NISHIYAMA over 3 years ago

In attached patch.diff

assert_equal({1=>2, 3=>4}, h.slice!(1, 3))

but ActiveSupport's h.slice!(1, 3) returns {5=>6}.

http://api.rubyonrails.org/classes/Hash.html#method-i-slice-21

#20 [ruby-core:56235] Updated by Nobuyoshi Nakada over 3 years ago

I've missed the returned values until I've implemented it actually.

  • In ActiveSupport

    • Hash#slice! keeps the given keys and returns removed key/value pairs.
    • Hash#except! removes the given keys and returns self.
  • In this proposal

    • Hash#slice! removes the given keys and returns removed key/value pairs.
    • Hash#except! is same as ActiveSupport.
  • Existing methods

    • Hash#select! keeps the given (by the block) keys and returns self or nil.
    • Hash#reject! removes the given (by the block) keys and returns self or nil.

I don't think changing the result semantics by if any arguments are given is good idea.
What I've thoutht about Hash#slice! was Hash#extract! in ActiveSupport actually.
So what about Hash#extract, Hash#except and those !-versions?

#21 [ruby-core:56242] Updated by Kenta Murata over 3 years ago

The attached file is not a part of my proposal. It made by Glass_saga. My proposal is the same as ActiveSupport.

#22 [ruby-core:56252] Updated by Masaki Matsushita over 3 years ago

I'm sorry for my wrong implementation.
patch2.diff makes Hash#slice! and #except! behave the same as ActiveSupport.
However, I think it isn't good idea to import Hash#slice! and #except! from ActiveSupport as it is.

Because:

  • They returns self if no changes were made. It is inconsistent with other built-in methods like #select! and #reject!.
  • #slice! returns rest of hash, not slice of hash like following. It may be confusing.
hash = {1=>2,3=>4,5=>6}
hash.slice!(1,3) #=> {5,6}
hash #=> {1=>2,3=>4}

#23 [ruby-core:60296] Updated by Hiroshi SHIBATA almost 3 years ago

  • Target version changed from 2.1.0 to current: 2.2.0

#24 [ruby-core:63275] Updated by Nobuyoshi Nakada over 2 years ago

  • Description updated (diff)

Another name, Hash#only.
http://blog.s21g.com/articles/228

#25 Updated by Koichi Sasada over 1 year ago

#26 [ruby-core:71381] Updated by Keith Bennett about 1 year ago

I was about to report this feature request but was happy to find that it was already there...but disappointed that it's been here so long. I'm using Ruby but not Rails and have been needing this functionality a lot lately.

Unless I'm misunderstanding, the implementation of such methods would be trivial. I would much rather see this implemented with a nonoptimal name than not implemented at all.

'slice' and 'except' are ok with me, but if there is a concern about their correctness as names, perhaps they could be 'select_if_key_in' and 'reject_if_key_in'.

But again, anything would be better than nothing.

#27 Updated by Shyouhei Urabe 5 months ago

Also available in: Atom PDF