Given an array containing numbers the following rules apply:
- a
0removes all previous numbers and all subsequent adjacent even numbers. - a
1removes all previous numbers and all subsequent adjacent odd numbers. - if the first element of the array is
1it can be removed
I am trying to write an algorithm to reduce the array but I could come up only with a bad looking solution:
def compress(array)
zero_or_one_index = array.rindex { |element| [0,1].include? element }
array.slice!(0, zero_or_one_index) if zero_or_one_index
deleting = true
while deleting
deleting = false
array.each_with_index do |element, index|
next if index.zero?
previous_element = array[index - 1]
if (previous_element == 0 && element.even?) ||
(previous_element == 1 && element.odd?)
array.delete_at(index)
deleting = true
break
end
end
end
array.shift if array[0] == 1
end
The problem is that delete_if and similar, start messing up the result, if I delete elements while iterating on the array, therefore I am forced to use a while loop.
Examples:
compress([3, 2, 0]) #=> [0]
compress([2, 0, 4, 6, 7]) #=> [0,7]
compress([2, 0, 4, 1, 3, 6]) #=> [6]
compress([3, 2, 0, 4, 1, 3, 6, 8, 5]) #=> [6,8,5]
This problem arises in the context of some refactorings I am performing on cancancan to optimize the rules definition.