Ruby hash equivalent to Python dict setdefault
A Hash can have a default value or a default Proc (which is called when a key is absent).
h = Hash.new("hi")
puts h[123] #=> hi
# change the default:
h.default = "ho"
In above case the hash stays empty.
h = Hash.new{|h,k| h[k] = []}
h[123] << "a"
p h # =>{123=>["a"]}
Hash.new([])
would not have worked because the same array (same as identical object) would be used for each key.
What's Ruby's equivalent to Python's setDefault()?
Ruby has the hash.fetch method, you can use it for the same way to gracefully handle missing keys, the difference is it doesn't then store those values:
h = {}
value = h.fetch(:some_key, [])
# value is now []
Another common way we accomplish what you are doing in Ruby is this:
h[:some_key] ||= []
or I guess you can even do this if you wanted to assign that to a value:
value = h[:some_key] ||= []
Setting ruby hash .default to a list
Hash.default
is used to set the default value returned when you query a key that doesn't exist. An entry in the collection is not created for you, just because queried it.
Also, the value you set default
to is an instance of an object (an Array in your case), so when this is returned, it can be manipulated.
a = {}
a.default = [] # set default to a new empty Array
a[8] << 9 # a[8] doesn't exist, so the Array instance is returned, and 9 appended to it
a.default # => [9]
a[9] # a[9] doesn't exist, so default is returned
Why dict.get(key) instead of dict[key]?
It allows you to provide a default value if the key is missing:
dictionary.get("bogus", default_value)
returns default_value
(whatever you choose it to be), whereas
dictionary["bogus"]
would raise a KeyError
.
If omitted, default_value
is None
, such that
dictionary.get("bogus") # <-- No default specified -- defaults to None
returns None
just like
dictionary.get("bogus", None)
would.
Set a value in a dict only if the value is not already set
This is a bit of a non-answer, but I would say the most pythonic is the if statement as you have it. You resisted the urge to one-liner it with __setitem__
or other methods. You've avoided possible bugs in the logic due to existing-but-falsey values which might happen when trying to be clever with short-circuiting and
/or
hacks. It's immediately obvious that the compute function isn't used when it wasn't necessary.
It's clear, concise, and readable - pythonic.
Set a value in a dict only if the value is not already set
This is a bit of a non-answer, but I would say the most pythonic is the if statement as you have it. You resisted the urge to one-liner it with __setitem__
or other methods. You've avoided possible bugs in the logic due to existing-but-falsey values which might happen when trying to be clever with short-circuiting and
/or
hacks. It's immediately obvious that the compute function isn't used when it wasn't necessary.
It's clear, concise, and readable - pythonic.
Does Python have an or equals function like ||= in Ruby?
Jon-Eric's answer's is good for dicts, but the title seeks a general equivalent to ruby's ||=
operator.
A common way to do something like ||=
in Python is
x = x or new_value
Ruby Hash Interaction With Pushing Onto Array
Read the Ruby Hash.new
documentation carefully - "if this hash is subsequently accessed by a key that doesn’t correspond to a hash entry, the value returned depends on the style of new used to create the hash".
new(obj) → new_hash
...If obj is specified, this single object will be used for all default values.
In your example you attempt to push something onto the value associated with a key which does not exist, so you end up mutating the same anonymous array you used to construct the hash initially.
the_array = []
h = Hash.new(the_array)
h['foo'] << 1 # => [1]
# Since the key 'foo' was not found
# ... the default value (the_array) is returned
# ... and 1 is pushed onto it (hence [1]).
the_array # => [1]
h # {} since the key 'foo' still has no value.
You probably want to use the block form:
new { |hash, key| block } → new_hash
...If a block is specified, it will be called with the hash object and the key, and should return the default value. It is the block’s responsibility to store the value in the hash if required.
For example:
h = Hash.new { |hash, key| hash[key] = [] } # Assign a new array as default for missing keys.
h['foo'] << 1 # => [1]
h['foo'] << 2 # => [1, 2]
h['bar'] << 3 # => [3]
h # => { 'foo' => [1, 2], 'bar' => [3] }
Related Topics
Calling the "Source" Command from Subprocess.Popen
How to Change an Image Size in Pygame
Display a 'Loading' Message While a Time Consuming Function Is Executed in Flask
Add Custom CSS Styling to Model Form Django
Is There an R Equivalent of the Pythonic "If _Name_ == "_Main_": Main()"
Create Static Graphics Files (Png, Gif, Jpg) Using Ruby or Python
Programmatically Extract Data from an Excel Spreadsheet
How to Perform Element-Wise Multiplication of Two Lists
How to Change the Default MySQL Connection Timeout When Connecting Through Python
What's the Best Way to Return Multiple Values from a Function
In Python, How to Import Filename Starts with a Number
Passing a Matplotlib Figure to HTML (Flask)
Best Way to Set Entry Background Color in Python Gtk3 and Set Back to Default
Equivalent of a Python Dict in R
Efficient Ways to Duplicate Array/List in Python
In Python Can One Implement Mixin Behavior Without Using Inheritance
How to Pickle a Python Function (Or Otherwise Serialize Its Code)