2017-03-10 56 views
0

我想比较两个散列和力量他们是平等的:比较两个哈希不管符号或字符串,轨道

  • 一个与键符号和
  • 第二用只有字符串。

如:

sym_hash = {:id=>58, :locale=>:"en-US"} 
string_hash = {"id"=>58, "locale"=>"en-US"} 

尝试这样不起作用:

> sym_hash == string_hash 
=> false 

我第一次尝试象征string_hash

> string_hash.deep_symbolize_keys 
=> {:id=>58, :locale=>"en-US"} 

,但它仍然是假b因为sym_hash仍然有:locale变种。

然后我试图字符串化sym_hash

> sym_hash.with_indifferent_access 
=> {"id"=>58, "locale"=>:"en-US"} 

但是,当我测试的平等仍然是false出于同样的原因。

编辑

要回答很多评论abouy 为什么我想这些哈希等于在这里,我将解释什么,我试图做的。

我使用Reque来管理我的工作。现在我想做一个班级,以避免同一个*作业正在运行,或者在同一时间内两次入队。

相同:对我来说,同样的工作是具有相同参数的工作,我希望能够有enqueu两次型动物同样的工作IDS的实例。)

对于我使用插件resque-status,到目前为止,我可以知道工作是否正在运行。除此之外,当我使用set保存参数时,我注意到写入Redis的消息(因为resis-status正在使用Redis来跟踪作业的状态)未正确保存为符号。

这里是我的类:

# This class is used to run thread-lock jobs with Resque. 
# 
# It will check if the job with the exact same params is already running or in the queue. 
# If the job is not finished, it will returns false, 
# otherwise, it will run and returns a the uuid of the job. 
# 
class JobLock 
    def self.run(obj, params = {}) 
    # Get rid of completed jobs. 
    Resque::Plugins::Status::Hash.clear_completed 
    # Check if your job is currently running or is in the queue. 
    if !detect_processing_job(obj, params) 
     job_uuid = obj.create(params) 
     Resque::Plugins::Status::Hash.set(job_uuid, 
             job_name: obj.to_s, 
             params: params) 
     job_uuid 
    else 
     false 
    end 
    end 

    def self.detect_processing_job(obj, params = {}) 
    Resque::Plugins::Status::Hash.statuses.detect do |job| 
     job['job_name'] == obj.to_s && compare_hashes(job['params'], params) 
    end 
    end 

    def self.compare_hashes(string_hash, sym_hash) 
    [sym_hash, string_hash].map do |h| 
     h.map { |kv| kv.map(&:to_s) }.sort 
    end.reduce :== 
    end 
end 

在这里,我如何使用它:

JobLock.run(MyAwesomeJob, id: 58, locale: :"en-US") 

正如你可以看到我用@ mudasobwa的答案,但我希望有一个更简单的方法来实现我正在尝试做什么!下面

+0

这些散列*** ***有不同 –

+0

是,在这种情况下,我想修改它们以使它们相似 –

+1

它不是一行代码(除非将它包装在方法中),但是您可以遍历哈希值并根据它们的'to_s'方法比较值。如果需要,我可以提供代码示例。 – MrDanA

回答

2

这个怎么样?

require 'set' 

def sorta_equal?(sym_hash, str_hash) 
    return false unless sym_hash.size == str_hash.size 
    sym_hash.to_a.to_set == str_hash.map { |pair| 
    pair.map { |o| o.is_a?(String) ? o.to_sym : o } }.to_set 
end 

sym_hash= {:id=>58, :locale=>:"en-US"} 

sorta_equal?(sym_hash, {"id"=>58, "locale"=>"en-US"})   #=> true 
sorta_equal?(sym_hash, {"locale"=>"en-US", "id"=>58 })   #=> true 
sorta_equal?(sym_hash, {"id"=>58, "local"=>"en-US", "a"=>"b" }) #=> false 
sorta_equal?(sym_hash, {"id"=>58, "lacole"=>"en-US"})   #=> false 
sorta_equal?(sym_hash, {"id"=>58, [1,2,3]=>"en-US"})   #=> false 
sorta_equal?({}, {})           #=> true 

class A; end 
a = A.new 
sorta_equal?({:id=>a, :local=>:b}, {"id"=>a, "local"=>"b"})  #=> true 
1

版本可以作为PHP力强制平等:

[sym_hash, string_hash].map do |h| 
    h.map { |kv| kv.map(&:to_s) }.sort 
end.reduce :== 

顺便说一句,这不是一个班轮只是因为我尊重的人使用智能手机。在宽度为80的终端上,它是一个完美的在线手册。

要强迫才串符号,保留NUMERICS从他们的字符串表示区分:

[sym_hash, string_hash].map do |h| 
    h.map { |kv| kv.map { |e| e.is_a?(Symbol) ? e.to_s : e } }.sort 
end.reduce :== 
+0

ty,yes无论如何,我并不关心单行程。所以它不存在一个方法来自动转换符合哈希键**和**值? –

+0

我希望它不存在。 – mudasobwa

+0

你希望?为什么?我的问题在于,我将第一个散列放入reddis缓存中,但是reddis不处理符号参数。也许我的问题更多的是XY问题。 –

0

localesym_hash的值是一个符号:"en-US", 而localestring_hash的值是一个字符串。 所以他们不平等。

现在,如果你这样做:

sym_hash = {:id=>58, :locale=>"en-US"} 
string_hash = {"id"=>58, "locale"=>"en-US"} 
string_hash.symbolize_keys! 
sym_hash == string_hash 
=> true 
+0

是的,我很清楚这个问题,这实际上是我的问题的关键:)我不能在动态重写哈希,因为它们在函数内部并且接受'params = {}'参数。 –

+0

我觉得比你需要循环散列 'string_hash.values.map(&:to_s)== sym_hash.values.map(&:to_s)' 或者你可以添加原始代码,所以我们可以有为了找到最好的解决方案,有一点上下文? – Zic

1

你可以尝试两种散列转换成JSON,然后对它们进行比较:

require 'json' 
# => true 
sym_hash = {:id=>58, :locale=>:"en-US"} 
# => {:id=>58, :locale=>:"en-US"} 
string_hash = {"id"=>58, "locale"=>"en-US"} 
# => {"id"=>58, "locale"=>"en-US"} 
sym_hash.to_json == string_hash.to_json 
# => true 
+0

当'string_hash = {“locale”=>“en-US”,“id”=> 58,}应该返回false,但应该返回true。 –

+0

更正:“...返回false但应返回true。” –

0

最后,为了回答我的问题,我并不需要强制哈希之间的比较。我用Marshal避免此类问题

class JobLock 
    def self.run(obj, params = {}) 
    # Get rid of completed jobs. 
    Resque::Plugins::Status::Hash.clear_completed 
    # Check if your job is currently running or is in the queue. 
    if !detect_processing_job(obj, params) 
     job_uuid = obj.create(params) 
     Resque::Plugins::Status::Hash.set(job_uuid, 
             job_name: obj.to_s, 
             params: Marshal.dump(params)) 
     job_uuid 
    else 
     false 
    end 
    end 

    def self.detect_processing_job(obj, params = {}) 
    Resque::Plugins::Status::Hash.statuses.detect do |job| 
     job['job_name'] == obj.to_s && Marshal.load(job['params']) == params 
    end 
    end 
end 

反正我在这里让这个问题,因为它可能会帮助一些人在未来...