Ruby 一起来做题: Get config values of hash

chenge · 2014年04月25日 · 最后由 chenge 回复于 2014年04月25日 · 3159 次阅读

题目来自 codewars,4kyu 级别难度。

Write a simple method for the Hash-class that can get the configuration-value from a JSON-interpreted hash. Its signature is:

Hash.get_value( default, key1, ... )

key1, ... refer to the hash-keys of the JSON-interpreted hash, which is a hash of hash values. If the path of keys is found, it should return the found value, else it should return the default value.

Here are some examples on how to use it:

config = { :files => { :mode => 0x777 }, :name => "config" }

config.get_value( 0x0, :files, :mode ) == 0x777 config.get_value( "", :name ) == "config" config.get_value( 80, :port ) == 80 config.get_value( "cfg", :files, :extension ) == "cfg"

我就贴个 java 风格的 ruby 代码让大家来耻笑吧,坐等楼下的一行流。

class Hash
  def get_value(default, *keys)

    hash_copy = self.clone

    if hash_copy.has_key?(keys[0])
      hash_copy = hash_copy[keys[0]]

      if hash_copy.is_a?(Hash)
        keys.shift
        hash_copy.get_value(default, *keys)
      elsif keys.size == 1
        hash_copy
      else
        default
      end

    else
      default
    end

  end
end

... #1 楼 @blacktulip 我觉得这个题递归很难无 BUG…… 你在非 hash 的时候没有看是否还有剩余的 keys……

#2 楼 @Kabie 额,说的是,反正楼主的 test 是 pass 了... 修改了一下检查剩余 keys。

匿名 #4 2014年04月25日

我当时写的(现在已经搞不懂为啥这么写了):

class Hash
  def get_value( default, *args )
    return default if args.empty?
    begin
      value = self
      loop do
        break value if args.empty?
        break default if !value.respond_to?(:fetch)
        value = value.fetch(args.shift)
      end
    rescue KeyError
      default
    end
  end
end

我说 codewars 怎么这么慢,原来一个 application-225c0ec0f6639a814d4c7e83507cfe55.js 竟然都快 500k 了……

为了一行已丧病,只保证跑通上面四个等式 _ (:з」∠)_

class Hash
    def get_value(default, *key_path)
        key_path.reduce(self) { |child, key| child.is_a?(Hash) ? child.fetch(key, default) : child }
    end
end

#5 楼 @saiga 好厉害,不过这个也没检查剩余 keys

#5 楼 @saiga fetch 不到会有异常的。

8 楼 已删除

#7 楼 @zgm 给了 default 就不抛异常了

fetch(key [, default] ) → obj
fetch(key) {| key | block } → obj

Returns a value from the hash for the given key. If the key can’t be found, there are several options: With no other arguments, it will raise an KeyError exception; if default is given, then that will be returned; if the optional code block is specified, then that will be run and its result returned.

我也来一个吧。

def get_value(default, *args)
  eval("self#{args.map{ |arg| "[:#{arg}]" }.join}") || default rescue default
end

#11 楼 @zgm 看不懂... 求详解

#12 楼 @blacktulip 应该不至于看不懂吧。

#13 楼 @zgm 噢... 看懂了,没想到可以拼字符串啊,还是你牛。

#14 楼 @blacktulip 这个有 bug 吗?

#15 楼 @zgm 有... 当 *args 为空时返回的不是 default 而是整个 hash

#11 楼 @zgm 这个可读性不好。self#什么意思?

#18 楼 @chenge 一旦想明白原理就会发现可读性其实很好... 比任何一楼的解答可读性都好

#5 楼 @saiga 这个感觉不错,可读性不错。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号