Project

General

Profile

Actions

Bug #10722

closed

Array#keep_if is borked if user calls 'break'

Added by wanabe (_ wanabe) over 9 years ago. Updated over 9 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.3.0dev (2015-01-09 trunk 49192) [x86_64-darwin14]
[ruby-dev:48805]

Description

ref. [Bug #2545]

$ ruby -e 'a = [5,6,7,8,9,10]; a.keep_if { |x| break if x > 8; x >= 7 }; p a'
[7, 8, 7, 8, 9, 10]
$ ruby -e 'a = [5,6,7,8,9,10]; a.delete_if { |x| break if x > 8; x < 7 }; p a'
[7, 8, 9, 10]

I was expecting the above scripts to be same results.


Related issues 2 (0 open2 closed)

Related to Ruby master - Bug #2545: Array#delete_if is borked if user calls 'break'Closedmatz (Yukihiro Matsumoto)01/02/2010Actions
Related to Ruby master - Feature #10714: Array#reject! nonlinear performance problemClosedakr (Akira Tanaka)01/08/2015Actions

Updated by wanabe (_ wanabe) over 9 years ago

  • Related to Bug #2545: Array#delete_if is borked if user calls 'break' added

Updated by nobu (Nobuyoshi Nakada) over 9 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

Applied in changeset r49196.


array.c: keep consistency

  • array.c (rb_ary_select_bang): keep the array consistent by
    removing unselected values soon. [ruby-dev:48805] [Bug #10722]

Updated by akr (Akira Tanaka) over 9 years ago

r49196 causes nonlinear performance problem.

% ./ruby -v -e '
20.times {|i|
  a = [nil]*i*10000;
  t1 = Time.now
  a.keep_if { false }
  t2 = Time.now
  t = t2 - t1
  p ["*" * (t * 20).to_i , t]
}
'
ruby 2.3.0dev (2015-01-10 trunk 49203) [x86_64-linux]
["", 2.229e-06]
["", 0.01375934]
["*", 0.052734738]
["**", 0.117660945]
["****", 0.209578563]
["******", 0.33836772]
["*********", 0.48799636]
["*************", 0.662050118]
["*****************", 0.876530968]
["**********************", 1.12094001]
["****************************", 1.402435918]
["**********************************", 1.709450864]
["*******************************************", 2.163054065]
["*************************************************", 2.480529295]
["************************************************************", 3.010499657]
["**********************************************************************", 3.535099527]
["***************************************************************************************", 4.389055292]
["*****************************************************************************************************", 5.053431719]
["*******************************************************************************************************", 5.190555455]
["***************************************************************************************************************", 5.59821402]

Updated by akr (Akira Tanaka) over 9 years ago

  • Related to Feature #10714: Array#reject! nonlinear performance problem added

Updated by akr (Akira Tanaka) over 9 years ago

Apart from the performance problem, I feel following exmaple should show [7,8].

a = [5,6,7,8,9,10]; a.keep_if { |x| break if x > 8; x >= 7 }; p a

Because the method name is "keep_if", the method should keep only elements which the block returns true.
The block doesn't return true since "break" for 9 and 10.
So they should not be keeped.

This is similar (but reversed) to nagachika's comment for delete_if:
https://bugs.ruby-lang.org/issues/2545#note-6

Updated by akr (Akira Tanaka) over 9 years ago

r49255 fixes the performance problem.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0