Ruby,将数组键转换为值

时间:2014-09-25 11:03:05

标签: ruby

我有一个像这样的简单数组:

stops = ["red_stop", "green_stop", "blue_stop", "yellow_stop", "purple_stop"]

我想确定两个'停止'之间的距离(停止次数)。我明白了:

stops.index("purple_stop")

将返回4,但我不明白如何编写一个Ruby方法,它将任意两个停止作为参数并计算它们之间的停止次数(例如“red_stop”是3次停止到“yellow_stop”< / p>

4 个答案:

答案 0 :(得分:2)

这很简单:

class Array
  def dist(a,b)
    (index(b) - index(a)).abs
  end
end

stops = ["red_stop", "green_stop", "blue_stop", "yellow_stop", "purple_stop"]
stops.dist('red_stop', 'blue_stop') #=> 2

但是请注意,如果您的数组有重复项,它将无效。

答案 1 :(得分:1)

使用它:

stops = ["red_stop", "green_stop", "blue_stop", "yellow_stop", "purple_stop"]

def getdiff(source, destination, stops)
 (stops.index(destination) - stops.index(source)).abs
end

getdiff("red_stop", "yellow_stop", stops)

答案 2 :(得分:0)

如果您需要所有组合:

stops = ["red_stop", "green_stop", "blue_stop", "yellow_stop", "purple_stop"]

stops.map.with_index { |s,i| [s,i] }
         .combination(2).each_with_object({}) { |((s1,d1),(s2,d2)),h|
           h[[s2,s1]] = h[[s1,s2]] = (d1-d2).abs }
  #=> {["red_stop",    "green_stop"] =>1, ["green_stop",  "red_stop"]   =>1,
  #    ["red_stop",    "blue_stop"]  =>2, ["blue_stop",   "red_stop"]   =>2,
  #    ["red_stop",    "yellow_stop"]=>3, ["yellow_stop", "red_stop"]   =>3,
  #    ["red_stop",    "purple_stop"]=>4, ["purple_stop", "red_stop"]   =>4,
  #    ["green_stop",  "blue_stop"]  =>1, ["blue_stop",   "green_stop"] =>1, 
  #    ["green_stop",  "yellow_stop"]=>2, ["yellow_stop", "green_stop"] =>2,
  #    ["green_stop",  "purple_stop"]=>3, ["purple_stop", "green_stop"] =>3, 
  #    ["blue_stop",   "yellow_stop"]=>1, ["yellow_stop", "blue_stop"]  =>1,
  #    ["blue_stop",   "purple_stop"]=>2, ["purple_stop", "blue_stop"]  =>2,
  #    ["yellow_stop", "purple_stop"]=>1, ["purple_stop", "yellow_stop"]=>1}

步骤如下:

a = stops.map.with_index { |s,i| [s,i] }
  #=> [["red_stop",    0], ["green_stop",  1], ["blue_stop", 2],
  #    ["yellow_stop", 3], ["purple_stop", 4]]

b = a.combination(2)
  #=> #<Enumerator: [["red_stop", 0], ["green_stop", 1], ["blue_stop", 2],
  #                  ["yellow_stop", 3], ["purple_stop", 4]]:combination(2)>

我们可以将枚举器b转换为数组以查看其元素:

b.to_a
  #=> [[["red_stop",    0], ["green_stop",  1]],
  #    [["red_stop",    0], ["blue_stop",   2]],
  #    [["red_stop",    0], ["yellow_stop", 3]],
  #    [["red_stop",    0], ["purple_stop", 4]],
  #    [["green_stop",  1], ["blue_stop",   2]],
  #    [["green_stop",  1], ["yellow_stop", 3]],
  #    [["green_stop",  1], ["purple_stop", 4]],
  #    [["blue_stop",   2], ["yellow_stop", 3]],
  #    [["blue_stop",   2], ["purple_stop", 4]],
  #    [["yellow_stop", 3], ["purple_stop", 4]]]

创建一个散列,其中包含每对的距离(不是块变量的分解):

b.each_with_object({}) { |((s1,d1),(s2,d2)),h|
  h[[s2,s1]] = h[[s1,s2]] = (d1-d2).abs }
  #=> {["red_stop", "green_stop"]=>1, ["green_stop", "red_stop"]=>1,
  #    ...
  #    ["yellow_stop", "purple_stop"]=>1, ["purple_stop", "yellow_stop"]=>1}

答案 3 :(得分:0)

stops的示例中,如果您的条目被视为双向,则假设为stops.dist(a,b) == stops.dist(b,a)。如果是这样,那么您已经获得了很好的答案,例如上面的@BroiSatse。

如果您的stops数组表示定向转换的节点或状态(例如在循环或有向图中),那么您可能需要dist方法来尊重它。换句话说,你的数组暗示要包裹。

class Array
  def dist(a,b)
    (index(b)-index(a)) % self.size
  end
end

stops = ["red_stop", "green_stop", "blue_stop", "yellow_stop", "purple_stop"]
stops.dist('red_stop', 'blue_stop')  #=> 2 (as expected)
stops.dist('blue_stop', 'red_stop')  #=> 3 (not 2, since it's directional)

交通灯状态的示例(转换是方向性的):

lights = ['green', 'yellow', 'red']
lights.dist('green', 'red')      #=> 2
lights.dist('red', 'green')      #=> 1 (green light follows a red light)

这取决于您尝试编码的域名。如果方向不重要,那么请忽略这个答案! ;-)祝你好运。