Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Destructive reject from an array returning the values rejected

Tags:

arrays

ruby

Is there a sensible way to do the following:

I want to take an array and select specific items from the array according to conditions, removing them from the array as they go. (I basically want to split the contents of an array into categories).

array = [1,2,3,4,5,6,7,8]

less_than_three = array.reject_destructively{|v| v<3}
=> [1,2]
array
=> [3,4,5,6,7,8]
more_than_five = array.reject_destructively{|v| v>5}
=> [6,7,8]
array
=> [3,4,5]

I've tried delete_if, select!, reject! and none of them seem to be able to give you the affected items whilst leaving the array with the rest. Unless I'm going mad, which is entirely possible.

like image 517
Carpela Avatar asked Aug 28 '15 14:08

Carpela


2 Answers

As I understood the question, you do not want to produce two new objects. Here you go:

class Array
  def carve!
    dup.tap { delete_if &Proc.new } - self
  end
end

array = [1,2,3,4,5,6,7,8]
p array.carve! { |v| v < 3 }
#⇒ [1, 2]                   # returned by Array#carve method
p array
#⇒ [3, 4, 5, 6, 7, 8]       # remained in original array

Using this solution, array.__id__ remains the same. And this is the golfiest answer all around :)

like image 109
Aleksei Matiushkin Avatar answered Nov 15 '22 05:11

Aleksei Matiushkin


You can build your own method for this...

class Array
  def extract(&block)
    temp = self.select(&block)
    self.reject!(&block)
    temp
  end
end

then...

a = [1, 2, 3, 4, 5]
a.extract{|x| x < 3}
=> [1,2]
p a
=> [3, 4, 5]

EDIT: If you don't want to monkey patch (but monkey patching isn't evil in itself) you can do it with a vanilla method...

def select_from_array(array, &block)
   temp = array.select(&block)
   array.reject!(&block)
   temp
end

array = [1,2,3,4,5,6,7,8]

less_than_three = select_from_array(array){|v| v<3}
=> [1,2]
array
=> [3,4,5,6,7,8]
more_than_five = select_from_array(array){|v| v>5}
=> [6,7,8]
array
=> [3,4,5]
like image 38
SteveTurczyn Avatar answered Nov 15 '22 05:11

SteveTurczyn