How to Remove All Elements That Satisfy a Condition in Array in Ruby

How to remove all elements that satisfy a condition in array in Ruby?

You can use either new_array = array.reject {|x| x < 3} (reject returns a new array) or array.reject! {|x| x < 3} (reject! aka delete_if modifies the array in place).

There's also the (somewhat more common) select method, which acts like reject except that you specify the condition to keep elements, not to reject them (i.e. to get rid of the elements less than 3, you'd use new_array = array.select {|x| x >= 3}).

How to remove all the elements after a particular index

Array#[]= operator comes in handy:

arr[n+1 .. -1] = []

In Ruby 2.6, you can also use endless ranges:

arr[n+1 ..] = []

Note that your code is slow, as it searches the array for every element and is thus O(n^2), but also wrong if the array contains repeating elements. For example, with arr = %w(10 20 30 10 20), your code does not change the array. This would be your code, only faster and correct (O(n); though the #[]= solution above is even faster and more straightforward):

arr.delete_if.with_index { |num, idx| idx > n }

How do I check that all the elements of an array satisfy a condition?

You can rewrite that as

arr.all? { |e| e.to_i >= 5 }

How do I remove the beginning elements of my array only if the first element satisfies a condition?

Sounds like you're trying to delete entities if they match their idx (provided the first idx is 0). Try this:

   if array.first == 0 
new_array = array.reject.each_with_index{ |item, idx| item == idx }
end

Although this will only work with ordered arrays of unique numbers, if you're not sure that they are then include: array = array.sort.uniq

find_all elements in an array that match a condition?

If I understand your question correctly, then I believe that the select method of Array class may be helpful to you.

select takes a block of code which is intended to be a test condition on each element in your array. Any elements within your array which satisfy that test condition will be selected, and the result is an array of those selected elements.

For example:

arr = [ 4, 8, 15, 16, 23, 42 ]
result = arr.select { |element| element > 20 }
puts result # prints out [23, 42]

In your example, you have an array of hashes, which makes it only slightly more complicated than my example with a simple array of numbers. In your example, we have:

data = [{A:'a1', B:'b1', C:'c1'}, 
{A:'a1', B:'b2', C:'c1'},
{A:'a1', B:'b2', C:'c2'},
{A:'a2', B:'b1', C:'c1'},
{A:'a2', B:'b2', C:'c1'}]

I believe what you want your code to do is something like: Select from my data array all of the hashes where, within the hash, :A equals some value AND :B equals some other value.

Let's say you want to find all of the hashes where :A == 'a1' and :B == 'b2'. You would do that like this:

data.select { |hash_element| hash_element[:A] == 'a1' && hash_element[:B] == 'b2' }

This line returns to you an array with those hashes from your original data array which satisfy the condition we provided in the block - that is, those hashes where :A == 'a1' and :B == 'b2'. Hope that that helps shed some light on your problem!

More information about the select method here:

http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-select

edited - below is an addition to original answer

To follow up on your later question about if/else clauses and the addition of new parameters... the block of code that you pass to select can, of course, be much more complicated than what I've written in the example. You just need to keep this in mind: If the last line of the block of code evaluates to true, then the element will be selected into the result array. Otherwise, it won't be selected.

So, that means you could define a function of your own, and call that function within the condition block passed to select. For example, something like this:

def condition_test(hash_element, key_values)
result = true
key_values.each do |pair|
if hash_element[pair[:key]] != pair[:value]
result = false
end
end
return result
end

# An example of the key-value pairs you might require to satisfy your select condition.
requirements = [ {:key => :A, :value => 'a1'},
{:key => :B, :value => 'b2'} ]

data.select { |hash_element| condition_test(hash_element, requirements) }

This makes your condition block a bit more dynamic, rather than hard-wired for :A == 'a1' and :B == 'b2' like we did in the earlier example. You can tweak requirements on the fly based on the keys and values that you need to look for. You could also modify condition_test to do more than just check to see if the hash value at some key equals some value. You can add in your if/else clauses in condition_test to test for things like the presence of some key, etc.

Checking if any element of an array satisfies a condition

Use Enumerable#any?

def has_dog?(acct)
[acct.title, acct.description, acct.tag].any? { |text| text.include? "dog" }
end

It will return true/false.

How do I split an array into smaller arrays bsaed on a condition?

One more way to skin a cat

def contains_vowel(v) 
v.count("aeiou") > 0
end
def split_by_substring_with_vowels(arr)
arr.chunk_while do |before,after|
!contains_vowel(before) & !contains_vowel(after)
end.to_a
end
split_by_substring_with_vowels(arr)
#=> [["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]

What it does:

  • passes each consecutive 2 elements
  • splits when either of them contain vowels

Example with your other Array

arr = ["1)", "dwr", "lyn,", "18,", "bbe"]
split_by_substring_with_vowels(arr)
#=> [["1)", "dwr", "lyn,", "18,"], ["bbe"]]

Further example: (if you want vowel containing elements in succession to stay in the same group)

def split_by_substring_with_vowels(arr)
arr.chunk_while do |before,after|
v_before,v_after = contains_vowel(before),contains_vowel(after)
(!v_before & !v_after) ^ (v_before & v_after)
end.to_a
end

arr = ["1)", "dwr", "lyn,", "18,", "bbe", "re", "rr", "aa", "ee"]
split_by_substring_with_vowels(arr)
#=> [["1)", "dwr", "lyn,", "18,"], ["bbe", "re"], ["rr"], ["aa", "ee"]]

This checks if before and after are both not vowels Or if they both are vowels

Exiting Ruby delete_if when false condition is satisfied

@@timestamp[@name].drop_while { |ts| ts <= Time.now - 5.minutes }

See: https://apidock.com/ruby/Array/drop_while:

Drops elements up to, but not including, the first element for which the block returns nil or false and returns an array containing the remaining elements.

There is also Array#take_while, in case you need to invert the logic.



Related Topics



Leave a reply



Submit