对象哈希的 Ruby 递归映射



我有一个哈希,它有一个未知的集合和嵌套数组、哈希、哈希数组和字符串的混合。这是JSON.parse的结果。数据的结构必须与开始时相同。最终目标是将字符串转换为可能是 Fixnum 的 Fixnum。

以下内容工作正常,但我想知道是否可以缩短它。请注意我如何需要 clean 方法中的键和值,因为并非所有可以是 Fixnum 的字符串都应该如此。有什么想法吗?

def clean_node(node)
    if node.class == String
      clean(node)
    elsif node.class == Array
      node.each_with_index do |obj, i|
        if obj.class == String
          node[i] = clean(node[i], obj)
        else
          clean_node(obj)
        end
      end
    elsif node.class == Hash
      node.each_pair do |key, value|
        if value.class == String
          node[key] = clean(key, value)
        else
          clean_node(value)
        end
      end
    end
end
def clean(key, value)
    FIXNUM_KEYS.include?(key)? value.to_i : value
end

无需拆分字符串处理,如果您在例程末尾返回 node 的值,则可以在一个递归例程中完成所有操作。这样做的副作用是删除一些参数,您可以使用就地.map!来处理数组。

使用 case 使按类型选择的内容稍微更容易阅读。

添加处理字符串数组的能力可以通过多种方式完成。我选择添加一个状态变量(递归中的常见模式,例如计算深度)。然后,在数组的情况下,递归从当前级别继承状态,而哈希大小写根据键列表中的查找确定新状态(转换或不转换)以应用转换。

def clean_node( node, convert_item = false )
    case node
    when String
      node = node.to_i if convert_item
    when Array
      node.map! do |obj| 
        clean_node( obj, convert_item )
      end
    when Hash
      node.each_pair do |key, value|
        node[key] = clean_node( value, FIXNUM_KEYS.include?(key) )
      end
    end
    node
end

虽然我没有研究递归,但我必须评论你正在编写 if 语句的事实,这些语句在 case 语句中更容易阅读:

def clean_node(node)
  case node
    when String then clean(node)
    when Array
      node.each_with_index do |obj, i|
        case obj
          when String
            node[i] = clean(node[i], obj)
          else
            clean_node(obj)
        end
      end
    when Hash....

最新更新