You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Ruby中如何扁平化嵌套哈希?动态键名场景下的快速实现

Flattening Nested Hashes in Ruby (with Dynamic Key Exclusion)

Hey there! Let's work through this nested hash flattening problem you're facing—since you need to skip specific keys and handle dynamic key names, a recursive approach is going to be your best bet here. It's flexible enough to adapt to changing key names and lets you easily exclude any keys you don't want in the final flattened hash.

Step 1: Basic Recursive Flattener with Key Exclusion

First, let's start with a core method that recursively traverses your nested hash, skips the specified keys, and flattens the structure. This works for most cases where you don't have duplicate key names across nested levels.

Example Nested Hash

Let's use a sample hash to test with:

nested_hash = {
  us: { name: "USA", population: 331_000_000 },
  au: { name: "Australia", population: 25_700_000 },
  eu: {
    de: { name: "Germany", population: 83_200_000 },
    ca: { name: "Canada", population: 38_000_000 },
    fr: { name: "France", population: 67_400_000 }
  }
}

The Flattening Method

def flatten_hash(hash, exclude_keys = [])
  hash.each_with_object({}) do |(key, value), result|
    # Skip any keys in our exclusion list
    next if exclude_keys.include?(key)
    
    if value.is_a?(Hash)
      # Recursively flatten nested hashes and merge into the result
      result.merge!(flatten_hash(value, exclude_keys))
    else
      # Add non-hash values directly to the result
      result[key] = value
    end
  end
end

How to Use It

Call the method with your hash and the list of keys to exclude:

flattened_result = flatten_hash(nested_hash, [:au, :ca])
puts flattened_result.inspect
# Output: {:name=>"USA", :population=>331000000, :name=>"Germany", :population=>83200000, :name=>"France", :population=>67400000}

Step 2: Handling Duplicate Keys (Optional)

Notice in the output above that duplicate keys like :name get overwritten (only the last one stays). If you want to preserve context from nested levels, you can modify the method to prepend parent keys as a prefix:

Updated Method with Key Prefixes

def flatten_hash(hash, exclude_keys = [], parent_prefix = "")
  hash.each_with_object({}) do |(key, value), result|
    next if exclude_keys.include?(key)
    
    # Build a unique key by combining parent prefix and current key
    current_key = parent_prefix.empty? ? key : "#{parent_prefix}_#{key}".to_sym
    
    if value.is_a?(Hash)
      # Pass the current key as the new parent prefix for recursion
      result.merge!(flatten_hash(value, exclude_keys, current_key))
    else
      result[current_key] = value
    end
  end
end

Test the Updated Version

flattened_result = flatten_hash(nested_hash, [:au, :ca])
puts flattened_result.inspect
# Output: {:us_name=>"USA", :us_population=>331000000, :eu_de_name=>"Germany", :eu_de_population=>83200000, :eu_fr_name=>"France", :eu_fr_population=>67400000}

Why This Works for Dynamic Key Names

Since we're passing the exclusion list as a parameter, you can easily update which keys to skip without modifying the method itself. For example, if next week you need to exclude :us and :fr instead, just call:

flatten_hash(nested_hash, [:us, :fr])

This approach is scalable for deeply nested hashes and keeps your code clean and maintainable.

内容的提问来源于stack exchange,提问作者Tintin81

火山引擎 最新活动