Search code examples
arraysrubyhashreturn-valuemultiple-return-values

Multiple return values with arrays and hashes


I believe arrays are mostly used for returning multiple values from methods:

def some_method
  return [1, 2]
end

[a, b] = some_method # should yield a = 1 and b = 2

I presume this is a kind of syntactic sugar that Ruby provides. Can we get a similar result with hashes, for instance

def some_method
  return { "a" => 1, "b" => 2 }
end

{"c", "d"} = some_method() # "c" => 1, "d" => 2

I'm looking for the result { "c" => 1, "d" => 2 }, which obviously does not happen. Is there any other way this can be done? I know that we can return a hash from the method and store it and use it like so

def some_method
  return {"a" => 1, "b" => 2}
end

hash = some_method()

Just curious if there is another way similar to the one with arrays but using hashes....


I think a simpler way to put the question would be...



    # If we have a hash
    hash = {"a" => 1, "b" => 2}

    # Is the following possible
    hash = {2, 3} # directly assigning values to the hash.
    OR
    # another example
    {"c", "d"} = {2, 3} # c and d would be treated as keys and {2, 3} as respective values.


Solution

  • What you are asking is syntactically not possible.

    What you want to accomplish is possible, but you will have to code it. One possible way to do that is shown below

    hash = {"a" => 1, "b" => 2}
    
    # Assign new keys
    new_keys = ["c", "d"]
    p [new_keys, hash.values].transpose.to_h
    #=> {"c"=>1, "d"=>2}
    
    # Assign new values
    new_values = [3, 4]
    p [hash.keys, new_values].transpose.to_h
    #=> {"a"=>3, "b"=>4}
    

    If you really want some more easier looking way of doing, you could monkey-patch Hash class and define new methods to manipulate the values of keys and values array. Please be cautioned that it may not be really worthwhile to mess with core classes. Anyways, a possible implementation is shown below. Use at your own RISK.

    class Hash
        def values= new_values
            new_values.each_with_index do |v, i|
                self[keys[i]] = v if i < self.size
            end
        end
        def keys= new_keys
            orig_keys = keys.dup
            new_keys.each_with_index do |k, i|
                if i < orig_keys.size
                    v = delete(orig_keys[i])
                    self[k] = v
                    rehash
                end
            end
        end
    end
    
    hash = {"a" => 1, "b" => 2}
    
    hash.values = [2,3]
    p hash
    #=> {"a"=>2, "b"=>3}
    
    hash.keys = ["c", "d"]
    p hash
    #=> {"c"=>2, "d"=>3}
    
    hash.keys, hash.values = ["x","y"], [9, 10]
    p hash
    #=> {"x"=>9, "y"=>10}
    
    hash.keys, hash.values = ["x","y"], [9, 10]
    p hash
    #=> {"x"=>9, "y"=>10}
    
    # *** results can be unpredictable at times ***
    hash.keys, hash.values = ["a"], [20, 10]
    p hash
    #=> {"y"=>20, "a"=>10}