搜索Ruby哈希表中的空值

10
我有一个像这样的Ruby哈希表: h = {"a" => "1", "b" => "", "c" => "2"} 现在我有一个Ruby函数,它评估这个哈希表并返回true,如果它发现一个键有一个空值。我有以下函数,即使哈希表中所有的键都不为空,它也始终返回true。
def hash_has_blank(hsh)  
  hsh.each do |k,v|  
    if v.empty?  
      return true  
    end  
  end
  return false
 end

我在这里做错了什么?


3
这对我来说很好用。你能举一个哈希表的例子吗?(因为你的"h"具有空值而导致问题出现) - DanSingerman
4个回答

25

试一下这个:

def hash_has_blank hsh
    hsh.values.any? &:empty?
end

或者:

def hash_has_blank hsh
    hsh.values.any?{|i|i.empty?}
end

如果您正在使用旧版本的 Ruby(1.8.x)


4
在Ruby >= 1.8.7中,您可以使用hsh.each_value.any? &:empty?来避免将哈希转换为数组。但这可能只在处理大型哈希时才有所影响。 - Konstantin Haase
警告:这将触发对响应empty?方法的哈希值的操作。例如,hash_has_blank({a: []}) == true,这可能不是预期的行为。@steenslag的建议通常更合适。 - Automatico
谢谢...那很有帮助。 - whitehat

8

我希望你准备好在这里学习一些Ruby的技巧。我不会像你那样全局定义这样的函数。如果它是一个哈希表操作,那么它应该是Hash类的实例方法,你可以这样做:

class Hash
  def has_blank?
    self.reject{|k,v| !v.nil? || v.length > 0}.size > 0
  end
end
reject会返回一个新的哈希表,其中包含所有空字符串,并检查这个新哈希表的大小。

可能更有效的方法(不应遍历整个数组):

class Hash
  def has_blank?
    self.values.any?{|v| v.nil? || v.length == 0}
  end
end

但是如果没有空值,这仍然会遍历整个哈希表。
我已经将 "empty?" 更改为 "!nil? || length > 0",因为我不知道你的 "empty" 方法是如何工作的。

1
不是很高效,因为你正在遍历整个哈希表,并且不必要地创建了另一个结构。 - Mladen Jablanović
你说得对,如果我更新我的答案。include? 不应该在发现一个 nil 的情况下遍历整个哈希表。但是,如果你几乎总是有不包含空值的哈希表,那么这根本不重要,因为为了返回 false,该函数必须始终遍历整个哈希表。 - jigfox
当没有空白时,任何解决方案都应该遍历整个哈希表。 - Mladen Jablanović

7

如果你只是想检查任何一个值是否为空字符串,你可以这样做:

h.has_value?('')

但是你的函数似乎工作得很好。

4
我建议您重构您的模型领域。很明显,哈希表示某种有形物品。为什么不将其变成一个对象呢?如果该项可以完全由哈希表示,则可以将其子类化为哈希。如果它更加复杂,则哈希可以是一个属性。
其次,检查空白的原因可以被命名为更好地反映您的领域。您没有告诉我们“为什么”,但让我们假设您的项目仅在没有任何空值时才有效。
class MyItem < Hash

  def valid?
    !invalid?
  end

  def invalid?
    values.any?{|i| i.empty?}
  end
end

重点是,如果你能建立一个在你的领域内有意义的词汇表,你的代码将更加清晰易懂。使用哈希表只是达到目的的一种手段,你最好使用更具描述性、与领域相关的术语。

以上面的示例为例,你可以这样做:

my_item = MyItem["a" => "1", "b" => "", "c" => "2"]

my_item.valid? #=> false

这是更干净的做法。jigfox的解决方案对我很有帮助。 - eabhvee
如果这只是一个临时脚本,那么可以接受。但在代码审查中,我会拒绝使用猴子补丁来修改基本数据结构,而更倾向于使用适当的对象建模。 - Mark Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接