Ruby数组迭代和变异

时间:2014-09-22 19:00:18

标签: ruby

我有一组类似的对象,其属性a可以包含值bc。可以将该数组视为行的集合,其中数组中的每对项表示一行。为简单起见,我刚刚列出了属性a的值, 例如:

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)
# ...

不能只有(b, b)行,如果是这种情况,则必须交换其中一个b值,以获得数组中最接近的c值。如果没有c个值,则只要b值保留在数组的末尾,该数组就有效。

数组的 final 行只能包含一个值,i。即(b,)。

示例:

 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, )    

这是我提出的解决方案,我不喜欢(因为它非常必要和冗长)

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

我遇到的一个问题是我在迭代时不能改变数组,需要两个循环。

编辑根据@ 7stud的建议清理部分中断语句。

1 个答案:

答案 0 :(得分:0)

Enumerable#chunk非常适合这个问题。

<强>代码

def valid?(arr, b)
  arr.chunk { |e| e }
     .map(&:last)[0..-2]
     .select { |e| e.first == b }
     .max_by(&:size)
     .size <= 2
end

示例

b = 0
c = 1
valid?([c, b, b, c, b, b, b], b) #=> true
valid?([c, b, b, b, c, c, b], b) #=> false

<强>解释

b = 0
c = 1
arr = [c, b, b, c, b, b, b]
  #=> [1, 0, 0, 1, 0, 0, 0]
enum = arr.chunk { |e| e }
  #=> #<Enumerator: #<Enumerator::Generator:0x0000010205aa70>:each>
enum.to_a # Let's examine the elements of `enum`
  #=> [[1, [1]], [0, [0, 0]], [1, [1]], [0, [0, 0, 0]]]
a = enum.map(&:last)
  #=> [[1], [0, 0], [1], [0, 0, 0]]
d = a[0..-2] # disregard last value, which may or may not be an array of `b`'s
  #=> [[1], [0, 0], [1]]
e = d.select { |e| e.first == b }
  #=> [[0, 0]]
f = e.max_by(&:size)
  #=> [0, 0]
g = f.size
  #=> 2
g <= 2
  #=> true