Comparing and returning dictionary string values? - python

Trying to make a function that returns a list of values from the dictionary. If the plants are watered weekly, it would be appended into the list then later returned sorted. However, my code iterates each letter of 'weekly' instead of the whole string and I have no idea how to access the watering frequency of the dictionary items. Any explanations would be appreciated.
def weekly(plants_d):
d = []
for plant in plants_d:
for plan in plants_d[plant]:
if plan == "weekly":
d.append[plan]
return sort(d)
weekly({'fern':'weekly', 'shamrock':'weekly', 'carnation':'weekly'})
# Should return like this: ['carnation','fern','shamrock']

Amending the previous answer so that only values with "weekly" are used:
>>> my_dict = {'fern':'weekly', 'shamrock':'weekly', 'carnation':'weekly', 'daffodil': 'monthly'}
>>> sorted(k for k, v in my_dict.items() if v == 'weekly')
['carnation', 'fern', 'shamrock']

This line:
for plan in plants_d[plant]:
is wrong. Since plants_d[plant] is a string like "weekly", this is like
for plan in "weekly":
which will iterate over the letters in the string. Then when you do if plan == "weekly": it will never match, because plan is just a single letter like "w".
You can simply use:
if plants_d[plan] == "weekly":
Or you can change the first loop to:
for plan_name, plan_frequency in plants_d.items():
if plan_frequency == "weekly":
d.append[plan_name]
See Iterating over dictionaries using 'for' loops

Simplified way to achieve this is using dict.keys() which return the list of all the keys in dict. In order to sort the list, you may use sorted() as:
>>> my_dict = {'fern':'weekly', 'shamrock':'weekly', 'carnation':'weekly'}
>>> sorted(my_dict.keys())
['carnation', 'fern', 'shamrock']
Edit: If some the plans are monthly, firstly filter the monthly plans using filter or dict comprehension. Your code should be like:
>>> my_dict = {'fern':'weekly', 'shamrock':'weekly', 'carnation':'weekly',
'something': 'monthly'}
# using filter() as #brianpck has already mentioned 'dict comprehension' approach
# It is better to use brian's approach
>>> filtered_dict = dict(filter(lambda x: x[1] == 'weekly', my_dict.items()))
>>> sorted(filtered_dict.keys())
['carnation', 'fern', 'shamrock']

Related

Function that makes dict from string but swaps keys and values?

I'm trying to make a function that takes in list of strings as an input like the one listed below:
def swap_values_dict(['Summons: Bahamut, Shiva, Chocomog',
'Enemies: Bahamut, Shiva, Cactaur'])
and creates a dictionary from them using the words after the colons as keys and the words before the colons as values. I need to clarify that, at this point, there are only two strings in the list. I plan to split the strings into sublists and, from there, try and assign them to a dictionary.
The output should look like
{'Bahamut': ['Summons','Enemies'],'Shiva':['Summons','Enemies'],'Chocomog':['Summons'],'Cactaur':['Enemies']}
As you can see, the words after the colon in the original list have become keys while the words before the colon (categories) have become the values. If one of the values appears in both lists, it is assigned two values in the final dictionary. I would like to be able to make similar dictionaries out of many lists of different sizes, not just ones that contain two strings. Could this be done without list comprehension and only for loops and if statements?
What I've Tried So Far
title_list = []
for i in range(len(mobs)):#counts amount of strings in list
titles = (mobs[i].split(":"))[0] #gets titles from list using split
title_list.append(titles)
title_list
this code returns ['Summons', 'Enemies'] which aren't the results I wanted to receive but I think they could help me write the function. I had planned on separating the keys and values into separate lists and then zipping them together afterwards as a dictionary.
Try:
def swap_values_dict(lst):
tmp = {}
for s in lst:
k, v = map(str.strip, s.split(":"))
tmp[k] = list(map(str.strip, v.split(",")))
out = {}
for k, v in tmp.items():
for i in v:
out.setdefault(i, []).append(k)
return out
print(
swap_values_dict(
[
"Summons: Bahamut, Shiva, Chocomog",
"Enemies: Bahamut, Shiva, Cactaur",
]
)
)
Prints:
{
"Bahamut": ["Summons", "Enemies"],
"Shiva": ["Summons", "Enemies"],
"Chocomog": ["Summons"],
"Cactaur": ["Enemies"],
}
I'd use a defaultdict. It saves you the trouble of manually checking if a key exists in your dictionary and constructing a new empty list, making for a rather concise function:
from collections import defaultdict
def swap_values_dict(mobs):
result = defaultdict(list)
for elem in mobs:
role, members = elem.split(': ')
for m in members.split(', '):
result[m].append(role)
return result

Changing a for loop to a dictionary comprehension

I get how to do regular comprehension style conversions for For loops, but this, I can't wrap my head around.
I know that normally you would change the lines 3-5 into one line, but is it possible to include the empty list in the comprehension?
The code is
text = input().lower()
dict = {}
for x in text:
if x.isalpha()
dict[x] = text.count(x)
print(dict)
I don't even know where to get started.
Don't use dict as a variable name, it's the name of a built-in function.
To convert the loop to a dictionary comprehension, change dict[key] = value to key: value, then follow it with the for loop and if condition.
text_dict = {x: text.count(x) for x in text if x.isalpha}
Note that Python has a standard library function collections.Counter() that does this.
from collections import Counter
text_dict = Counter(filter(str.isapha, text))
By referring to the dictionary comprehension posted by #Barmar, another way to do so is using dictionary comprehension and set:
result = dict((x,text.count(x)) for x in set(text.lower()) if x.isalpha)

Python - How to create sublists from list of strings based on part of the string?

I saw similar questions but unfortunately I didnt found answer for my problem.
I have a list:
list = ['a_abc', 'a_xyz', 'a_foo', 'b_abc', 'b_xyz', 'b_foo']
I want to split this list into 3 based on character after underscore _.
Desired output would be:
list_1 = ['a_abc', 'b_abc']
list_2 = ['a_xyz', 'b_xyz']
list_3 = ['a_foo', 'b_foo']
I would like to avoid something like:
for element in list:
if 'abc' in element...
if 'xyz' in element...
because I have over 200 strings to group in this way in my use case. So code "should recognize" the same part of the string (after underscore) and group this in sublists.
Since I didnt notice similar issue any advice is highly appreciated.
You shouldn't want to do this with one or more lists, because you don't know at runtime how many there are (or, even if you know, it will be repeated code).
Instead, you can use defaultdict; it's like a default dictionary, but handles missing value simply creating a new element with your specified factory.
In this case, defaultdict(list) means to create a dictionary with a list factory; when a key is missing, the object will create an empty list for that key.
from collections import defaultdict
l = ['a_abc', 'a_xyz', 'a_foo', 'b_abc', 'b_xyz', 'b_foo']
d = defaultdict(list)
for el in l:
key = el.split("_")[1]
# key = el[2:] # use this if the format of elements is <letter>_<other_chars>
d[key].append(el)
print(d)
# defaultdict(<class 'list'>, {'abc': ['a_abc', 'b_abc'], 'xyz': ['a_xyz', 'b_xyz'], 'foo': ['a_foo', 'b_foo']})
print(d["abc"])
# ['a_abc', 'b_abc']

Python: How to traverse a List[Dict{List[Dict{}]}]

I was just wondering if there is a simple way to do this. I have a particular structure that is parsed from a file and the output is a list of a dict of a list of a dict. Currently, I just have a bit of code that looks something like this:
for i in xrange(len(data)):
for j, k in data[i].iteritems():
for l in xrange(len(data[i]['data'])):
for m, n in data[i]['data'][l].iteritems():
dostuff()
I just wanted to know if there was a function that would traverse a structure and internally figure out whether each entry was a list or a dict and if it is a dict, traverse into that dict and so on. I've only been using Python for about a month or so, so I am by no means an expert or even an intermediate user of the language. Thanks in advance for the answers.
EDIT: Even if it's possible to simplify my code at all, it would help.
You never need to iterate through xrange(len(data)). You iterate either through data (for a list) or data.items() (or values()) (for a dict).
Your code should look like this:
for elem in data:
for val in elem.itervalues():
for item in val['data']:
which is quite a bit shorter.
Will, if you're looking to decend an arbitrary structure of array/hash thingies then you can create a function to do that based on the type() function.
def traverse_it(it):
if (isinstance(it, list)):
for item in it:
traverse_it(item)
elif (isinstance(it, dict)):
for key in it.keys():
traverse_it(it[key])
else:
do_something_with_real_value(it)
Note that the average object oriented guru will tell you not to do this, and instead create a class tree where one is based on an array, another on a dict and then have a single function to process each with the same function name (ie, a virtual function) and to call that within each class function. IE, if/else trees based on types are "bad". Functions that can be called on an object to deal with its contents in its own way "good".
I think this is what you're trying to do. There is no need to use xrange() to pull out the index from the list since for iterates over each value of the list. In my example below d1 is therefore a reference to the current data[i].
for d1 in data: # iterate over outer list, d1 is a dictionary
for x in d1: # iterate over keys in d1 (the x var is unused)
for d2 in d1['data']: # iterate over the list
# iterate over (key,value) pairs in inner most dict
for k,v in d2.iteritems():
dostuff()
You're also using the name l twice (intentionally or not), but beware of how the scoping works.
well, question is quite old. however, out of my curiosity, I would like to respond to your question for much better answer which I just tried.
Suppose, dictionary looks like: dict1 = { 'a':5,'b': [1,2,{'a':100,'b':100}], 'dict 2' : {'a':3,'b':5}}
Solution:
dict1 = { 'a':5,'b': [1,2,{'a':100,'b':100}], 'dict 2' : {'a':3,'b':5}}
def recurse(dict):
if type(dict) == type({}):
for key in dict:
recurse(dict[key])
elif type(dict) == type([]):
for element in dict:
if type(element) == type({}):
recurse(element)
else:
print element
else:
print dict
recurse(dict1)

How to retrieve from python dict where key is only partially known?

I have a dict that has string-type keys whose exact values I can't know (because they're generated dynamically elsewhere). However, I know that that the key I want contains a particular substring, and that a single key with this substring is definitely in the dict.
What's the best, or "most pythonic" way to retrieve the value for this key?
I thought of two strategies, but both irk me:
for k,v in some_dict.items():
if 'substring' in k:
value = v
break
-- OR --
value = [v for (k,v) in some_dict.items() if 'substring' in k][0]
The first method is bulky and somewhat ugly, while the second is cleaner, but the extra step of indexing into the list comprehension (the [0]) irks me. Is there a better way to express the second version, or a more concise way to write the first?
There is an option to write the second version with the performance attributes of the first one.
Use a generator expression instead of list comprehension:
value = next(v for (k,v) in some_dict.iteritems() if 'substring' in k)
The expression inside the parenthesis will return an iterator which you will then ask to provide the next, i.e. first element. No further elements are processed.
How about this:
value = (v for (k,v) in some_dict.iteritems() if 'substring' in k).next()
It will stop immediately when it finds the first match.
But it still has O(n) complexity, where n is the number of key-value pairs. You need something like a suffix list or a suffix tree to speed up searching.
If there are many keys but the string is easy to reconstruct from the substring, then it can be faster reconstructing it. e.g. often you know the start of the key but not the datestamp that has been appended on. (so you may only have to try 365 dates rather than iterate through millions of keys for example).
It's unlikely to be the case but I thought I would suggest it anyway.
e.g.
>>> names={'bob_k':32,'james_r':443,'sarah_p':12}
>>> firstname='james' #you know the substring james because you have a list of firstnames
>>> for c in "abcdefghijklmnopqrstuvwxyz":
... name="%s_%s"%(firstname,c)
... if name in names:
... print name
...
james_r
class MyDict(dict):
def __init__(self, *kwargs):
dict.__init__(self, *kwargs)
def __getitem__(self,x):
return next(v for (k,v) in self.iteritems() if x in k)
# Defining several dicos ----------------------------------------------------
some_dict = {'abc4589':4578,'abc7812':798,'kjuy45763':1002}
another_dict = {'boumboum14':'WSZE x478',
'tagada4783':'ocean11',
'maracuna102455':None}
still_another = {12:'jfg',45:'klsjgf'}
# Selecting the dicos whose __getitem__ method will be changed -------------
name,obj = None,None
selected_dicos = [ (name,obj) for (name,obj) in globals().iteritems()
if type(obj)==dict
and all(type(x)==str for x in obj.iterkeys())]
print 'names of selected_dicos ==',[ name for (name,obj) in selected_dicos]
# Transforming the selected dicos in instances of class MyDict -----------
for k,v in selected_dicos:
globals()[k] = MyDict(v)
# Exemple of getting a value ---------------------------------------------
print "some_dict['7812'] ==",some_dict['7812']
result
names of selected_dicos == ['another_dict', 'some_dict']
some_dict['7812'] == 798
I prefer the first version, although I'd use some_dict.iteritems() (if you're on Python 2) because then you don't have to build an entire list of all the items beforehand. Instead you iterate through the dict and break as soon as you're done.
On Python 3, some_dict.items(2) already results in a dictionary view, so that's already a suitable iterator.

Categories