【问题标题】:Am I able to use each_cons(2).any? with hash values?我可以使用 each_cons(2).any 吗?哈希值?
【发布时间】:2014-10-02 20:49:44
【问题描述】:

如果我有一个整数数组并希望检查一个值是否小于前一个值。我正在使用:

array = [1,2,3,1,5,7]
con = array.each_cons(2).any? { |x,y| y < x }
p con

这会返回 true,正如预期的那样,因为 1 小于 3。

我将如何检查一个哈希值是否小于前一个哈希值?

hash = {"0"=>"1", "1"=>"2","2"=>"3","4"=>"1","5"=>"5","6"=>"7"}

我仍在学习 Ruby,非常感谢您的帮助。

【问题讨论】:

  • 您的哈希包含字符串,您的数组整数。这是设计使然吗?此外,由于哈希被认为是无序的,你的意思是按键排序吗?如果是整数,这些排序会更好。
  • 哈希在 Ruby 1.9+ 中按插入排序
  • @Max:哈希保留插入顺序,但将它们视为有序集合 IMO 通常仍然是个坏主意。 (实际上,我认为给他们这种半生不熟的排序行为是个坏主意,因为它使它在简单的情况下工作,要么尴尬,要么意外地闯入更复杂的情况,而不仅仅是保持一致,但那匹马摆脱了很久以前的谷仓。)
  • @Chuck 我同意,但这就是问题所在。 tadman 听起来好像这个问题没有明确定义,我只是指出由于保留了插入顺序,它是明确定义的
  • 抱歉,我已经将它们转换为整数,因为我有 {1=&gt;564}

标签: ruby hashmap


【解决方案1】:

如果要查找是否所有元素都符合条件,从数组开始:

array = [1,2,3,1,5,7]
con = array.each_cons(2).all? { |x,y| x < y }
con # => false

更改数组,使元素都小于下一个:

array = [1,2,3,4,5,7]
con = array.each_cons(2).all? { |x,y| x < y }
con # => true

对于数组元素和散列,许多方法的行为相似,因此基本代码是相同的,它们传递到块中的方式发生了变化。我将哈希减少到最低限度来演示代码:

hash = {"3"=>"3","4"=>"1","5"=>"5"}
con = hash.each_cons(2).all? { |(_, x_value), (_, y_value) |  x_value < y_value }
con # => false

将哈希更改为递增:

hash = {"3"=>"3","4"=>"4","5"=>"5"}
con = hash.each_cons(2).all? { |(_, x_value), (_, y_value) |  x_value < y_value }
con # => true

使用any? 会以同样的方式工作。如果你想知道有没有&gt;=

hash = {"3"=>"3","4"=>"1","5"=>"5"}
con = hash.each_cons(2).any? { |(_, x_value), (_, y_value) |  y_value >= x_value }
con # => true

或者:

hash = {"3"=>"3","4"=>"4","5"=>"5"}
con = hash.each_cons(2).any? { |(_, x_value), (_, y_value) |  x_value >= y_value }
con # => false

我正在通过

创建哈希
stripped = Hash[x.scan(/(\w+): (\w+)/).map { |(first, second)| [first.to_i, second.to_i] }]

然后我将删除空数组

new = stripped.delete_if { |elem| elem.flatten.empty? }

这不是使用scan 的好方法。考虑这些:

'1: 23'.scan(/\d+/) # => ["1", "23"]
'1: 23'.scan(/(\d+)/) # => [["1"], ["23"]]
'1: 23'.scan(/(\d+): (\d+)/) # => [["1", "23"]]

首先,scan 返回一个值数组。在第二个中,它返回一个数组数组,其中每个子数组都是一个元素。在第三个中,它返回一个数组数组,其中每个子数组包含扫描的两个元素。您正在使用第三种形式,这不必要地使之后所做的一切复杂化。

不要使传递给scan 的模式复杂化,而是依靠它在查看字符串时返回多个匹配元素并返回这些元素的数组的能力:

'1: 23'.scan(/\d+/) # => ["1", "23"]

在此基础上构建:

'1: 23'.scan(/\d+/).map(&:to_i) # => [1, 23]
Hash[*'1: 23'.scan(/\d+/).map(&:to_i)] # => {1=>23}

注意Hash[] 中的前导*。那个“splat”告诉 Ruby 将数组爆裂或分解成它的组件。如果它不存在,会发生以下情况:

Hash['1: 23'.scan(/\d+/).map(&:to_i)] # => {} # !> this causes ArgumentError in the next release

最后,如果您不需要哈希元素是整数,这与您在问题中给出的哈希相矛盾,只需从上面的示例中删除 .map(&amp;:to_i)

【讨论】:

  • 我正在通过stripped = Hash[x.scan(/(\w+): (\w+)/).map { |(first, second)| [first.to_i, second.to_i] }] 创建哈希然后我通过new = stripped.delete_if { |elem| elem.flatten.empty? } 删除空数组然后我希望返回小于前一个哈希的第一个哈希值的键价值
  • 循环哈希并返回小于前一个值的第一个值的键的最佳方法是什么。我之前使用的是.each_cons(2).any? { |x,y| y &lt; x }。但我似乎无法正确构造它以循环遍历哈希
  • 基本上就是这样。你想“find第一个值的键......”所以查看Enumerable类,并阅读方法的描述,直到你“find”返回第一个匹配条件的。注意:Stack Overflow 不是分发代码,而是帮助你解决问题,所以你需要尝试,然后在尝试不起作用时提出问题。
【解决方案2】:

首先,从散列中分离出值:

values = hash.map { |key, value| value.to_i } #=> [1, 2, 3, 1, 5, 7]

或:

values = hash.values.map(&:to_i) #=> to_i is a shortcut for:
values = hash.values.map { |value| value.to_i }

然后执行与数组示例相同的操作。

【讨论】:

  • 在这种情况下,to_a 调用是多余的。
  • to_a 将哈希转换为双精度数组,其中每个数组元素是键和值。 @tadman 是的,你是对的,删除它,.map 似乎在引擎盖后面转换它。
  • 是的,map 这样很方便。
  • hash.values 怎么样?或者hash.values.map(&amp;:to_i),如果你必须转换它们。
  • 也添加了这些,不确定他是否会被 to_i 弄糊涂,所以我添加了一个解释。
猜你喜欢
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-15
  • 2022-01-03
  • 2013-05-13
  • 1970-01-01
  • 2011-05-08
相关资源
最近更新 更多