I have an array of similar objects, with an attribute a which can have values b or c. The array can be considered as a collection of rows, where each pair of items in the array represent one row. I've just listed the values of attribute a for simplicity's sake,
Example:
array = [c, b, b, c, c, c, b]
# array[0], array[1] is one row (c, b)
# array[2], array[3] is another (b, c)
# ...
There can be no row of just (b, b), and if that is the case then one of the b values must be swapped for the closest c value in the array. If there are no more c values, then the array is valid as long as the b values are left at the end of the array.
The final row of the array can consist of just one value, i. e. (b, ).
Example:
array = [b, c, b, b, c, b, b, b, c, b, b, c, c]
# becomes
array = [b, c, b, c, b, b, b, b, c, b, b, c, c]
array = [b, c, b, c, b, c, b, b, b, b, b, c, c]
array = [b, c, b, c, b, c, b, c, b, b, b, b, c]
array = [b, c, b, c, b, c, b, c, b, c, b, b, b]
# rows: (b, c), (b, c), (b, c), (b, c), (b, c), (b, b,), (b, )
This is the solution I came up with, which I don't really like (because it's very imperative and verbose)
while true do
cand = nil
array.each_slice(2) do |item, nxt|
return if nxt.nil?
# pseudo-code: assume b? returns true for a == b
next unless item.b? && nxt.b?
cand = nxt
break
end
swap_cand = array.slice(array.index(cand), array.length).reject{ |item| item.popular? }.first
return if swap_cand.nil?
old_index, new_index = array.index(cand), array.index(swap_cand)
array[old_index], array[new_index] = array[new_index], array[old_index]
end
A problem I kept running into was that I couldn't mutate an array while iterating over it, necessitating two loops.
edit Cleaned up some of the break statements per the suggestions from @7stud.
return done = true if nxt.nil?Huh? Do you know what a LocalJumpError is? If the code you posted is actually inside a def, then what does setting done=true do for you? When you return from a def, there's no more loop--no more nothing.donevariable and subsequently exit theeach_sliceloop. This is indeed inside a function definition, and as specified by theuntilloop this outer loop exits whendoneistrue.