Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

AddArray#extract!#33137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
matthewd merged 3 commits intorails:masterfrombogdanvlviv:add-array-extract-method
Aug 14, 2018
Merged

Conversation

@bogdanvlviv
Copy link
Contributor

@bogdanvlvivbogdanvlviv commentedJun 14, 2018
edited
Loading

The method removes and returns the elements for which the block returns a true value.
If no block is given, an Enumerator is returned instead.

numbers=[0,1,2,3,4,5,6,7,8,9]odd_numbers=numbers.extract!{ |number|number.odd?}# => [1, 3, 5, 7, 9]numbers# => [0, 2, 4, 6, 8]

Also, I added commitUseArray#extract! where possible in order to show that we can improve Rails code base by this method.

- nils, values = values.partition(&:nil?)- ranges, values = values.partition { |v| v.is_a?(Range) }+ nils = values.extract!(&:nil?)+ ranges = values.extract! { |v| v.is_a?(Range) }

Looks more readable if useArray#extract!, doesn't it?

I know we try to omit adding new methods to ActiveSupport, but I think this one has a good chance to be added since we can apply it in Rails code base.
By the way, we already addedHash#extract!
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/hash/slice.rb#L41-L47

Post:https://gitlab.com/bogdanvlviv/posts/-/issues/14,https://bogdanvlviv.com/posts/ruby/rails/array-extract-to-activesupport-6-0.html

I have tried to add Active Support'sArray#extract! asArray#extract to Ruby, seeFeature #15831: "AddArray#extract,Hash#extract, andENV.extract".

Thanks!

abarrak, patrols, joshuapinter, pedrosfdcarneiro, and markokajzer reacted with thumbs up emojijoshuapinter, jestemkarol, and IvanNosov reacted with hooray emoji
@rails-bot
Copy link

r?@schneems

(@rails-bot has picked a reviewer for you, use r? to override)

@rafaelfranca
Copy link
Member

I'm ok with this one.@dhh what do you think of this name?

@dhh
Copy link
Member

dhh commentedJun 14, 2018 via email

I like it! 👍
On Jun 14, 2018, at 23:07, Rafael França ***@***.***> wrote: I'm ok with this one.@dhh what do you think of this name? — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

@sikachu
Copy link
Member

I honestly thought that this is whatselect! does, but apparently not. So, 👍from me too.

@matthewd
Copy link
Member

FWIW, it would be namedextract upstream... but as we already haveHash#extract!: 🤷🏻‍♂️

Also, I added commit Use Array#extract! where possible in order to show that we can improve Rails code base by this method.

💯. This was very helpful, thank you.

On the implementation: I'd like to avoid allocating the second array. What do you think of something likereject! { |el| extracted_elements << el if yield el } ?

Let's also avoidunless/else in favour of an early return; the double-negative of thatelse can be confusing, even though the code layout is nearly the same.

@bogdanvlviv
Copy link
ContributorAuthor

bogdanvlviv commentedJun 15, 2018
edited
Loading

Thanks for the review guys!

@matthewd I applied your suggestions inRefactorArray#extract!.

On the implementation: I'd like to avoid allocating the second array. What do you think of something like reject! { |el| extracted_elements << el if yield el } ?

I prepared benchmarks in order to ensure that the changes speed up the method: (Not sure that these benchmarks are completely right)

beginrequire"bundler/inline"rescueLoadError=>e  $stderr.puts"Bundler version 1.10 or later is required. Please updateyour Bundler"raiseeendclassArraydefextract_v1!(&block)unlessblock_given?to_enum(:extract!){size}elseextracted_elements,other_elements=partition(&block)replace(other_elements)extracted_elementsendenddefextract_v2!returnto_enum(:extract!){size}unlessblock_given?extracted_elements=[]reject!do |element|extracted_elements <<elementifyield(element)endextracted_elementsendendgemfile(true)dosource"https://rubygems.org"gem"benchmark-ips"endarrays_for_partition=Array.new(1000){(0..10000).to_a}arrays_for_extract_v1=Array.new(1000){(0..10000).to_a}arrays_for_extract_v2=Array.new(1000){(0..10000).to_a}Benchmark.ipsdo |x|x.report("Array#partition")doarrays_for_partition.eachdo |numbers|odd_numbers,numbers=numbers.partition{ |number|number.odd?}numbersendendx.report("Array#extract_v1!")doarrays_for_extract_v1.eachdo |numbers|odd_numbers=numbers.extract_v1!{ |number|number.odd?}numbersendendx.report("Array#extract_v2!")doarrays_for_extract_v2.eachdo |numbers|odd_numbers=numbers.extract_v2!{ |number|number.odd?}numbersendendx.compare!end

The result of the benchmarks:

ruby -vruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
Fetching gem metadata from https://rubygems.org/.Resolving dependencies...Using benchmark-ips 2.7.2Using bundler 1.16.1Warming up --------------------------------------     Array#partition     1.000  i/100ms   Array#extract_v1!     1.000  i/100ms   Array#extract_v2!     1.000  i/100msCalculating -------------------------------------     Array#partition      1.390  (± 0.0%) i/s -      7.000in   5.044843s   Array#extract_v1!      2.781  (± 0.0%) i/s -     14.000in   5.050589s   Array#extract_v2!      3.151  (± 0.0%) i/s -     16.000in   5.080608sComparison:   Array#extract_v2!:        3.2 i/s   Array#extract_v1!:        2.8 i/s - 1.13x  slower     Array#partition:        1.4 i/s - 2.27x  slower

Let's also avoid unless/else in favour of an early return; the double-negative of that else can be confusing, even though the code layout is nearly the same.

Yeah, It will be more readable and also using of early return would improvegit diff
in some cases if we needed to change this method I think.

@sikachu
Copy link
Member

I rerun the test case (twice, in the span of 6 days ..ha) and it is now passing.@matthewd@rafaelfranca would either of you mind merging this in if this is good to go?

Edouard-chin reacted with thumbs up emoji

@bogdanvlvivbogdanvlvivforce-pushed theadd-array-extract-method branch from0a8e9ef to58abeedCompareJuly 5, 2018 21:29
The method removes and returns the elements for which the block returns a true value.If no block is given, an Enumerator is returned instead.```numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]numbers # => [0, 2, 4, 6, 8]```
Avoid allocating the second array by using `Array#reject!` instead of`Enumerable#partition` in `Array#extract!`.There are benchmarks in order to ensure that the changes speed up the method:```begin  require "bundler/inline"rescue LoadError => e  $stderr.puts "Bundler version 1.10 or later is required. Please updateyour Bundler"  raise eendclass Array  def extract_v1!(&block)    unless block_given?      to_enum(:extract!) { size }    else      extracted_elements, other_elements = partition(&block)      replace(other_elements)      extracted_elements    end  end  def extract_v2!    return to_enum(:extract!) { size } unless block_given?    extracted_elements = []    reject! do |element|      extracted_elements << element if yield(element)    end    extracted_elements  endendgemfile(true) do  source "https://rubygems.org"  gem "benchmark-ips"endarrays_for_partition = Array.new(1000) { (0..10000).to_a }arrays_for_extract_v1 = Array.new(1000) { (0..10000).to_a }arrays_for_extract_v2 = Array.new(1000) { (0..10000).to_a }Benchmark.ips do |x|  x.report("Array#partition")  do    arrays_for_partition.each do |numbers|      odd_numbers, numbers = numbers.partition { |number| number.odd? }      numbers    end  end  x.report("Array#extract_v1!")  do    arrays_for_extract_v1.each do |numbers|      odd_numbers = numbers.extract_v1! { |number| number.odd? }      numbers    end  end  x.report("Array#extract_v2!")  do    arrays_for_extract_v2.each do |numbers|      odd_numbers = numbers.extract_v2! { |number| number.odd? }      numbers    end  end  x.compare!end```The result of the benchmarks:```ruby -vruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]``````Fetching gem metadata fromhttps://rubygems.org/.Resolving dependencies...Using benchmark-ips 2.7.2Using bundler 1.16.1Warming up --------------------------------------     Array#partition     1.000  i/100ms   Array#extract_v1!     1.000  i/100ms   Array#extract_v2!     1.000  i/100msCalculating -------------------------------------     Array#partition      1.390  (± 0.0%) i/s -      7.000  in   5.044843s   Array#extract_v1!      2.781  (± 0.0%) i/s -     14.000  in   5.050589s   Array#extract_v2!      3.151  (± 0.0%) i/s -     16.000  in   5.080608sComparison:   Array#extract_v2!:        3.2 i/s   Array#extract_v1!:        2.8 i/s - 1.13x  slower     Array#partition:        1.4 i/s - 2.27x  slower```Avoid `unless`/`else` in favour of an early return.The double-negative of that `else` can be confusing,even though the code layout is nearly the same.Also using of early return would improve `git diff`if we needed to change this method.
@matthewdmatthewd merged commit7fa2f53 intorails:masterAug 14, 2018
@bogdanvlvivbogdanvlviv deleted the add-array-extract-method branchAugust 14, 2018 17:32
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@sikachusikachusikachu approved these changes

@rafaelfrancarafaelfrancarafaelfranca approved these changes

Assignees

@schneemsschneems

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

7 participants

@bogdanvlviv@rails-bot@rafaelfranca@dhh@sikachu@matthewd@schneems

[8]ページ先頭

©2009-2025 Movatter.jp