0

I have an array in which I want to filter its elements, and mutate it to remove that elements, not only that I need that filtering to return a new array with the filtered elements, something like this:

array = [1, 2]
rejected_elements = array.rejection_method! {|a| a == 1} => [1]
rejected_elements => [1]
array => [2]

Is there any built in method in Ruby to do so?

Here is what I have tried:

dupped_array = array.dup
rejected_elements = array.reject! {|a| a == 1} 
array = dupped_array - rejected_elements

But I have an array that contains nested hashes, and duplicating it won't be a good idea, and will cause me hell. So I asked if there is any built in method or good way to do this straight forward.

davidhu
  • 9,523
  • 6
  • 32
  • 53
Wazery
  • 15,394
  • 19
  • 63
  • 95
  • 1
    "I have an array that contains nested hashes, and duplicating it won't be a good idea, and will cause me hell." In what way will it cause you hell? – Jordan Running Sep 08 '16 at 20:01
  • consider the answer to http://stackoverflow.com/questions/38314478/ruby-array-delete-if-and-get-deleted-object (yes, it's my question, but I dealt with something like this just a few months ago, so it rang a bell)... – jaydel Sep 08 '16 at 20:30

4 Answers4

2

maybe something like this ?

array = [1,2,3,4,5,6,7]
rejected = array.map { |a| array.delete(a) if  a.even? }.compact
Bartłomiej Gładys
  • 4,525
  • 1
  • 14
  • 24
1

I don't know if there's a built-in method that does this. Array#reject! and Array#delete_if modify the array but do not return the rejected elements. So here's a custom method that does what you request:

def rej_method(arr, n)
  a = arr - arr.reject {|i| i==n }
  arr.delete(n)
  a
end

Then as per your example:

array = [1, 2]
rejected_elements = rej_method(array, 1)
rejected_elements #=> [1]
array             #=> [2]

Consider using the Enumerable#partition method, example:

arr =  [1, 2, 3, 4, 5] 
arr.partition {|i| i==1 } #=> [[1], [2, 3, 4, 5]] 
Sagar Pandya
  • 9,323
  • 2
  • 24
  • 35
  • 1
    Enumerable#partition is how I approached a similar problem and it was concise and easy to use. `arr1, arr2 = arr.partition...` did the trick nicely. – jaydel Sep 08 '16 at 20:32
  • @jaydel nice, I didn't realise you could use parallel assignment like that with a 2D array- thanks. – Sagar Pandya Sep 08 '16 at 23:38
0

If you don't mind reassigning array, you could do something like this:

array = [1, 2]
predicate = ->(member) { member == 1 }
array, rejects = array.inject([[],[]]) { |(keep, discard), member| 
  if predicate.call(member)
    [keep, discard.push(member)]
  else
    [keep.push(member), discard]
  end
}

array => [2]
rejects => [1]
pdoherty926
  • 9,895
  • 4
  • 37
  • 68
0
def remove_ns(arr, n)
  [n]*(arr.size - ((arr.delete(n) || arr) && arr).size)
end

arr = [1,2]
remove_ns arr, 1
  #=> [1] 
arr
  #=> [2]

arr = [1,1,2,2]
remove_ns arr, 1
  #=> [1, 1] 
arr
  #=> [2, 2] 

arr = [1,2]
remove_ns arr, 3
  #=> [] 
arr
  #=> [1, 2] 
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100