I have a dictionary like:
Data = {
"weight_factors" : {
"parameter1" : 10,
"parameter2" : 30,
"parameter3" : 30
},
"other_info" : {
}
}
I want to get the sum of all values that are under the key "weight_factors":
sum = Data["weight_factors"]["parameter1"] +
Data["weight_factors"]["parameter2"] +
Data["weight_factors"]["parameter3"]
Currently, in order to avoid entering Data["weight_factors"] repeatedly, I use the following commands:
d = Data["weight_factors"]
d["parameter1"] + d["parameter2"] + d["parameter3"]
But, I guess there should be an operator that does the same thing, without storing Data["weight_factors"] as an intermediate variable. I was wondering if such a command or an operator exists.
Data["weight_factors"]<unknown operator>(["parameter1"] +
["parameter2"] +
...
["parametern"])<unknown operator>
EDIT:
In the example given above, it was just a sum operation. But it could for example be:
Data["weight_factors"]["parameter1"] * Data["weight_factors"]["parameter2"] + Data["weight_factors"]["parameter3"]
But I do not want enter Data["weight_factors"] repeatedly. That's the thing I am searching for... I don't know whether such an operator exists. (In MATLAB, there exists such a thing for cell structures).
No, that kind of operator does not exist for the built-in dict type.
I suppose you could make your own dict type that inherited from dict and overloaded an operator:
class MyDict(dict):
def __add__(self, other):
"""Overload the + operator."""
...
but that is somewhat inefficient and not very good for readability.
If you just want to sum the values, you can use sum and dict.values (dict.itervalues if you are using Python 2.x):
>>> Data = {
... "weight_factors" : {
... "parameter1" : 10,
... "parameter2" : 30,
... "parameter3" : 30
... },
... "other_info" : {
... }
... }
>>> sum(Data["weight_factors"].values())
70
>>>
Otherwise, I would just use what you have now:
d = Data["weight_factors"]
myvar = d["parameter1"] * d["parameter2"] + d["parameter3"]
It is about as clean and efficient as you can get.
For a general solution to repeatedly get the same item from a mapping or index, I suggest the operator module's itemgetter:
>>> import operator
>>> Data = {
"weight_factors" : {
"parameter1" : 10,
"parameter2" : 30,
"parameter3" : 30
},
"other_info" : {
}
}
Now create our easy getter:
>>> get = operator.itemgetter('weight_factors')
And call it on the object whenever you want your sub-dict:
>>> get(Data)['parameter1']
returns:
10
and
>>> sum(get(Data).values())
returns
70
If this is just "how do I access a dict's values easily and repeatedly?" you should just assign them like this, and you can reuse them again and again.
In Python 2:
vals = Data['weight_factors'].values()
In Python 3, values returns an iterator, which you can't reuse, so materialize it in a list:
vals = list(Data['weight_factors'].values())
and then you can do whatever you want with it:
sum(vals)
max(vals)
min(vals)
etc...
Related
With (some) Pythons built-in types, is it possible to refer to the object we are declaring ?
By "(some) built-in types" I think about, for example, sequence types, mapping types or set types, obviously not numeric types.
I mean, without creating a class myself and adding this functionality (without creating a subclass).
So, something like the this keyword as used in the examples below.
For example, for the "dict" Python built-in type, something like this:
a_dictionary = {
"key_1": "value_1",
"key_2": "value_2",
"key_3": this["key_1"] + "_" + this["key_2"] # == "value_1_value_2"
}
or even:
a_dictionary = {
"sub_dict_1": {
"key_1": "value_1_1",
"key_2": "value_1_2",
"key_3": this["key_1"] + "_" + this["key_2"] # == "value_1_1_value_1_2"
},
"sub_dict_2": {
"key_1": "value_2_1",
"key_2": "value_2_2",
"key_3": this["key_1"] + "_" + this["key_2"] # == "value_2_1_value_2_2"
}
}
I've read :
When doing function chaining in python, is there a way to refer to the "current" object?
What do I do when I need a self referential dictionary?
Reference a dictionary within itself
Self-referencing classes in python?
Is there a way to refer to the current function in python?
Is it possible to access current object while doing list/dict comprehension in Python?
and some others, but it doesn't match up the requirements described at the begining of my question.
Thanks a lot for your help!
Python provides no way to refer to an object under construction by a literal or a display*. You can (ab)use the assignment expression in Python 3.8 or later to simulate this:
a_dictionary = {
"key_1": (x := "value_1"),
"key_2": (y := "value_2"),
"key_3": x + "_" + y
}
It requires some planning ahead, as you are not referring to a key value directly, rather a pre-defined variable. Notice that x and y remain in scope after the assignment to a_dictionary, so this is just a questionable equivalent of
x = "value_1"
y = "value_2"
a_dictionary = {
"key_1": x,
"key_2": y,
"key_3": x + "_" + y
}
A custom class would really be more appropriate:
class Thing:
def __init__(self, v1, v2):
self.key_1 = v1
self.key_2 = v2
self.key_3 = v1 + "_" + v2
a_thing = Thing("value_1", "value_2")
A display is a construct like a literal, but could contain non-literal references. For example, list displays include [1, x, y] and [int(x) for x in foo].
After some digging, and only for the case of a dictionary, I found this other workaround, based on What do I do when I need a self referential dictionary? :
class MyDict(dict):
def __getitem__(self, item):
return dict.__getitem__(self, item).format(self)
a_dictionary = MyDict({
"key_1": "value_1",
"key_2": "value_2",
"key_3": "{0[key_1]}" + "_" + "{0[key_2]}" # == "value_1_value_2"
})
I'm writing some printouts for the debug mode of a script. Is there a compact way to print the names of those variables in a list that meet a condition?
specification_aw3 = 43534
specification_hg7 = 75445
specification_rt5 = 0
specification_nj8 = 5778
specification_lo4 = 34
specification_ee2 = 8785
specification_ma2 = 67
specification_pw1 = 1234
specification_mu6 = 0
specification_xu8 = 12465
specifications = [
specification_aw3,
specification_hg7,
specification_rt5,
specification_nj8,
specification_lo4,
specification_ee2,
specification_ma2,
specification_pw1,
specification_mu6,
specification_xu8
]
if any(specification == 0 for specification in specifications):
# magic code to print variables' names
# e.g. "variables equal to 0: \"specification_rt5\", \"specification_mu6\"
Just as 9000 suggests, it goes without saying that defining a dictionary is a rational approach for the minimal working example I have defined here. Please assume that this is not a feasible option for the existing code project and that I am looking for a quick, compact (plausibly ugly) bit of code to be used solely for debugging.
EDIT: illustration of something similar to what I want
So here's the beginnings of what I'm looking for:
print("specifications equal to zero:")
callers_local_objects = inspect.currentframe().f_back.f_locals.items()
for specification in [specification for specification in specifications if specification == 0]:
print([object_name for object_name, object_instance in callers_local_objects if object_instance is specification][0])
Basically, is there a compact way to do something like this?
I suggest that instead of a bunch of variables you use a dict:
specification = {
'aw3': 0,
'foo': 1,
'bar': 1.23,
# etc
}
You can access things by name like specification['aw3'].
Then you can find out names for which the value is 0:
zeroed = [name for (name, value) in specification.items() if value == 0]
In addition, since you mentioned printing the line would be:
for element in specification_dictionary:
print(element)
where you can combine it with a list comprehension as above for printing only the elements that meet your case. Element in this case only prints the variable name (key) if you want both the key and value just set it to use specification_dictionary.items(). Cheers.
>>> specification = { 'aw3': 0, 'foo': 1}
>>> for element in specification:
... print(element)
...
foo
aw3
>>> for (key, value) in specification.items():
... print(str(key) + " " + str(value))
...
foo 1
aw3 0
>>> for element in specification.items():
... print(element)
...
('foo', 1)
('aw3', 0)
So say that I have a dictionary with a default value of another dictionary
attributes = { 'first_name': None, 'last_name': None, 'calls': 0 }
accounts = defaultdict(lambda: attributes)
The problem is that the default dictionary that I pass into defaultdict (attributes) is passed as a reference. How can I pass it as a value? So that changing the values in one key doesn't change the values in other keys
For example -
accounts[1]['calls'] = accounts[1]['calls'] + 1
accounts[2]['calls'] = accounts[2]['calls'] + 1
print accounts[1]['calls'] # prints 2
print accounts[2]['calls'] # prints 2
I want each of them to print 1, since I only incremented their respective values for 'calls' once.
Try:
accounts = defaultdict(attributes.copy)
Since Python 3.3 listss also have copy method so you can use it the same way as above with defaultdicts when you need a dict with a list as a default value.
I really like warvariuc's solution. However, remember, you are not passing a dict into defaultdict... that would result in a TypeError, because that argument must be a callable. You could have just used a literal in a lambda. Or better yet, define a helper function:
>>> def attribute():
... return { 'first_name': None, 'last_name': None, 'calls': 0 }
...
>>> accounts = defaultdict(attribute)
>>> accounts[1]['calls'] = accounts[1]['calls'] + 1
>>> accounts[2]['calls'] = accounts[2]['calls'] + 1
>>> print(accounts[1]['calls'])
1
>>> print(accounts[2]['calls'])
1
I have a nested dictionary called "high_low_teams_in_profile" which looks like this:
{
m_profile1:
{
team_size1:
{
low: 1,
high: 1
},
team_size2:
{
low: 1,
high: 1
}
},
m_profile2:
{
team_size1:
{
low: 1,
high: 1
},
team_size2:
{
low: 1,
high: 1
}
}
}
And I want to get {m_profile1: 4, m_profile2: 4}
What is the most eloquent way to do it in python?
Right now I have the following:
new_num_teams_in_profile = {}
for profile in high_low_teams_in_profile:
new_num_teams_in_profile[profile]= dict((team_size, sum(high_low_teams_in_profile[profile][team_size].values())) for team_size in high_low_teams_in_profile[profile])
new_num_teams_in_profile= dict((profile, sum(new_num_teams_in_profile[profile].values())) for profile in new_num_teams_in_profile)
I'm not sure if I'd say it's the most Pythonic, but it's the most functional:
p = high_low_teams_in_profile
{ prof:sum(p[prof][team][hl]
for team in p[prof]
for hl in p[prof][team])
for prof in p}
The arguments of sum is a generator expression and the outer { prof:sum(...) for prof in p} is a dictionary comprehension.
While this may not be the most pythonic, the following code should work and is more readable than your original version. Note the iteritems() method, which allows access to both the keys and values of the dict, while itervalues(), as the name suggests, only iterates the values of the dict.
final = {}
for key, sizes in high_low_teams_in_profile.iteritems():
total = 0
for value in sizes.itervalues():
s = sum(value.itervalues())
total += s
final[key] = total
print final
In addition, you could use the following. While it is a shorter number of lines, it is slightly more difficult to read.
final = {}
for key, sizes in high_low_teams_in_profile.iteritems():
total = sum([sum(value.itervalues()) for value in sizes.itervalues()])
final[key] = total
print final
I have a dictionary in Python where the keys are pathnames. For example:
dict["/A"] = 0
dict["/A/B"] = 1
dict["/A/C"] = 1
dict["/X"] = 10
dict["/X/Y"] = 11
I was wondering, what's a good way to print all "subpaths" given any key.
For example, given a function called "print_dict_path" that does this, something like
print_dict_path("/A")
or
print_dict_path("/A/B")
would print out something like:
"B" = 1
"C" = 1
The only method I can think of is something like using regex and going through the entire dictionary, but I'm not sure if that's the best method (nor am I that well versed in regex).
Thanks for any help.
One possibility without using regex is to just use startswith
top_path = '/A/B'
for p in d.iterkeys():
if p.startswith(top_path):
print d[p]
You can use str.find:
def print_dict_path(prefix, d):
for k in d:
if k.find(prefix) == 0:
print "\"{0}\" = {1}".format(k,d[k])
Well, you'll definitely have to loop through the entire dict.
def filter_dict_path( d, sub ):
for key, val in d.iteritems():
if key.startswith(sub): ## or do you want `sub in key` ?
yield key, val
print dict(filter_dict_path( old_dict, sub ))
You could speed this up by using the appropriate data structure: a Tree.
Is your dictionary structure fixed? It would be nicer to do this using nested dictionaries:
{
"A": {
"value": 0
"dirs": {
"B": {
"value": 1
}
"C": {
"value": 1
}
}
"X": {
"value": 10
"dirs": {
"Y": {
"value": 11
}
}
The underlying data structure here is a tree, but Python doesn't have that built in.
This removes one level of indenting, which may make the code in the body of the for loop more readable in some cases
top_path = '/A/B'
for p in (p for p in d.iterkeys() if p.startswith(top_path)):
print d[p]
If you find performance to be a problem, consider using a trie instead of the dictionary