【问题标题】:Ruby array iteration and mutationRuby 数组迭代和变异
【发布时间】:2014-09-22 19:00:17
【问题描述】:

我有一个类似对象的数组,属性a 可以有值b 或c。可以将数组视为行的集合,其中数组中的每一对项目代表一行。为简单起见,我刚刚列出了属性 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 行可以只包含 一个 值,即。 e. (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

我一直遇到的一个问题是我无法在迭代数组时对其进行变异,因此需要两个循环。

edit根据@7stud 的建议清理了一些中断语句。

【问题讨论】:

  • return done = true if nxt.nil? 嗯?你知道 LocalJumpError 是什么吗?如果您发布的代码实际上在 def 中,那么设置 done=true 对您有什么作用?当你从 def 返回时,没有更多的循环——没有更多的东西。
  • 我假设这会简单地设置done 变量,然后退出each_slice 循环。这确实在函数定义中,并且由until 循环指定,当done 为true 时,此外部循环退出。
  • 我一直遇到的一个问题是我无法在迭代数组时对其进行变异。 `结果 = [];温度 = []; arr.each 做 |obj|结果
  • @7stud 是的,我也这样做了,但这看起来和我最终得出的结果一样丑陋甚至更丑陋。如果您有更好的建议,我将不胜感激。
  • @7stud 你知道有两个循环,对吗?

标签: ruby


【解决方案1】:

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

【讨论】:

  • 感谢分享,您介意解释一下这种方法如何交换值并转换数组吗?
  • 我将这个问题解释为仅确定数组是否“有效”,而不涉及任何交换。那是对的吗?顺便说一句,当你发表评论时,我正在准备解释。
  • 很抱歉,如果不清楚!这是来自问题(猜它有点隐藏)If there is an occurrence of three b values in a row, one of the b values need to be swapped for the closest c value in order for the array to adhere to the rules if one exists.
  • 好的,但我不认为“最接近”是明确的。例如,如果arr = [b,c,b,b,c,b,b,b,c,b,b,c,c],期望的结果是什么?
  • 好点,我已经更新了我的问题,希望能减少混乱!
猜你喜欢
  • 1970-01-01
  • 2018-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-04
  • 2016-07-10
  • 2016-05-16
  • 1970-01-01
相关资源
最近更新 更多