Nested lists with dictionaries based on condition - python

I feel like i'm loosing my mind over this...
So I have added comments twice because i think i'm not really making sense. The code I have is more psuedocode because I have been going in circles.
The idea is to have a list of items that have a dictionary containing various prices, with various quantity's according to that price. Ideally I want to insert them in order of the name, then in order of the price
Here is what I have so far.
MyList = []
print(MyList)
def insertIntoList(listToAdd):
"""insert into MyList if name not in first element of each list
if the name is in the list, check to see if the first element of
any dictionary has the same value, if it does, add the last element
to the last element of that dictionary element"""
if len(MyList) == 0:
MyList.append(listToAdd)
for ind, i in enumerate(listToAdd):
#for each list in listToAdd
if i in MyList:
#if name in MyList
for item in listToAdd[1][0]:
if item in MyList[ind] == listToAdd[1][0]:
#if the first element of each dictionary
# in the list is equivalent to the first element
# of the dict, then increment the last element
MyList += listToAdd[1][1]
else:
#otherwise add the new dictionary to the list
MyList.append(listToAdd[1])
else:
#otherwise if name isnt in MyList
MyList.append(listToAdd)
insertIntoList(["Foo", [{1010:10101010}]])
insertIntoList(["Bar", [{0:1}]])
insertIntoList(["Bar", [{1:1}]])
insertIntoList(["Foo", [{1010:5}]])
print(MyList)
This should print;
[["Bar", [{0:1}, {1:1}]], ["Foo", [{1010:10101015}]]]

Perhaps you should use a better data structure like,
$ cat price.py
from collections import defaultdict
d = defaultdict(dict)
def insert(key, value):
for k,v in value.items():
d[key].setdefault(k, 0)
d[key][k] += v
insert("Foo", {1010:10101010})
insert("Bar", {0:1})
insert("Bar", {1:1})
insert("Foo", {1010:5})
print(dict(d))
print([[key, [{k:v} for k,v in value.items()]] for key,value in d.items()])
Since, the data to be inserted is based on the key, a dict should be apt here.
And you could shape it to be however you want in the end like,
Output:
$ python price.py
'Foo': {1010: 10101015}, 'Bar': {0: 1, 1: 1}}
[['Foo', [{1010: 10101015}]], ['Bar', [{0: 1}, {1: 1}]]]

You could do something like this
def insert(result, key, price, quantity):
priceDict = result.get(key, {price: 0})
priceDict[price] += quantity
result[key] = priceDict
return result
result = {}
print(result) # {}
insert(result, "Foo", 1010, 10101010)
insert(result, "Bar", 0, 1)
insert(result, "Foo", 1010, 5)
print(result) # {'Foo': {1010: 10101015}, 'Bar': {0: 1}}

Related

Write a function to add key-value pairs

I'd like to write a function that will take one argument (a text file) to use its contents as keys and assign values to the keys. But I'd like the keys to go from 1 to n:
{'A': 1, 'B': 2, 'C': 3, 'D': 4... }.
I tried to write something like this:
Base code which kind of works:
filename = 'words.txt'
with open(filename, 'r') as f:
text = f.read()
ready_text = text.split()
def create_dict(lst):
""" go through the arg, stores items in it as keys in a dict"""
dictionary = dict()
for item in lst:
if item not in dictionary:
dictionary[item] = 1
else:
dictionary[item] += 1
return dictionary
print(create_dict(ready_text))
The output: {'A': 1, 'B': 1, 'C': 1, 'D': 1... }.
Attempt to make the thing work:
def create_dict(lst):
""" go through the arg, stores items in it as keys in a dict"""
dictionary = dict()
values = list(range(100)) # values
for item in lst:
if item not in dictionary:
for value in values:
dictionary[item] = values[value]
else:
dictionary[item] = values[value]
return dictionary
The output: {'A': 99, 'B': 99, 'C': 99, 'D': 99... }.
My attempt doesn't work. It gives all the keys 99 as their value.
Bonus question: How can I optimaze my code and make it look more elegant/cleaner?
Thank you in advance.
You can use dict comprehension with enumerate (note the start parameter):
words.txt:
colorless green ideas sleep furiously
Code:
with open('words.txt', 'r') as f:
words = f.read().split()
dct = {word: i for i, word in enumerate(words, start=1)}
print(dct)
# {'colorless': 1, 'green': 2, 'ideas': 3, 'sleep': 4, 'furiously': 5}
Note that "to be or not to be" will result in {'to': 5, 'be': 6, 'or': 3, 'not': 4}, perhaps what you don't want. Having only one entry out of two (same) words is not the result of the algorithm here. Rather, it is inevitable as long as you use a dict.
Your program sends a list of strings to create_dict. For each string in the list, if that string is not in the dictionary, then the dictionary value for that key is set to 1. If that string has been encountered before, then the value of that key is increased by 1. So, since every key is being set to 1, then that must mean there are no repeat keys anywhere, meaning you're sending a list of unique strings.
So, in order to have the numerical values increase with each new key, you just have to increment some number during your loop:
num = 0
for item in lst:
num += 1
dictionary[item] = num
There's an easier way to loop through both numbers and list items at the same time, via enumerate():
for num, item in enumerate(lst, start=1): # start at 1 and not 0
dictionary[item] = num
You can use this code. If an item has been in the lst more than once, the idx is considered one time in dictionary!
def create_dict(lst):
""" go through the arg, stores items in it as keys in a dict"""
dictionary = dict()
idx = 1
for item in lst:
if item not in dictionary:
dictionary[item]=idx
idx += 1
return dictionary

Couting value in list inside of a list

I want to count identical values in my lists in list.
already I coded it:
id_list = [['cat','animal'],['snake','animal'], ['rose','flower'], ['tomato','vegetable']]
duplicates = []
for x in range(len(id_list)):
if id_list.count(id_list[x][1]) >= 2:
duplicates.append(id_list[x][1])
print(duplicates)
I think it don't work becouse the count is counting id[x][1] and don't seen any other values in rest of lists.
If there any way to count my lists instead of value of that list but leaning on this value?
Thank for all help and advice
Have a nice day!
You can get the count of all the elements from your list in a dictionary like this:
>>> id_list = [['cat','animal'],['snake','animal'], ['rose','flower'], ['tomato','vegetable']]
>>> {k: sum(id_list, []).count(k) for k in sum(id_list, [])}
{'cat': 1, 'animal': 2, 'snake': 1, 'rose': 1, 'flower': 1, 'tomato': 1, 'vegetable': 1}
You can extract the elements whose value (count) is greater than 1 to identify as duplicates.
Explanation: sum(id_list, []) basically flattens a list of lists, this would work for any number of elements inside your inner lists. sum(id_list, []).count(k) stores the count of every k inside this flattened list and stores it in a dictionary with k as key and the count as value. You can iterate this dictionary now and select only those elements whose count is greater than, let’s say 1:
my_dict = {k: sum(id_list, []).count(k) for k in sum(id_list, [])}
for key, count in my_dict.items():
if count > 1:
print(key)
or create the dictionary directly by:
flat_list = sum(id_list, [])
>>> {k: flat_list.count(k) for k in flat_list if flat_list.count(k) > 1}
{'animal': 2}
How about this:
id_list = [['cat','animal'],['snake','animal'], ['rose','flower'], ['tomato','vegetable']]
els = [el[1] for el in id_list]
[k for k,v in {i:els.count(i) for i in els }.items() if v > 1]
['animal']
Kr

write a function which accepts a list of tuple objects and returns a dictionary containing the sum of values of all the strings

Continue from the previous question, write a function called get_sum(tuple_list) which accepts a list of tuple objects and returns a dictionary containing the sum of values of all the strings that appear in the list. For example, if we have the following data (a list of tuple objects):
tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
then the dictionary should contain the following:
{'a': 10, 'b': 20}
My problem is how to distinguish a b value when sum them together
Test
tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
sum_dict = get_sum(tuple_list)
for key in sorted(sum_dict.keys()):
print("{}: {}".format(key, sum_dict[key]))
Result
a: 10
b: 20
I would suggest to use defauldict. You can use a normal dict but it will take some more if statements.
from collections import defaultdict
d = defaultdict(int)
tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
for a,b in tuple_list:
d[a] +=b
print (d)
#defaultdict(<class 'int'>, {'a': 10, 'b': 20})
If you want to use your original method, you can use tuple unpacking:
def get_sum(l):
new_dict = {}
for x, y in l:
if x not in new_dict:
new_dict[x] = y
else:
new_dict[x] +=y
return new_dict
print (get_sum(tuple_list))
#{'a': 10, 'b': 20}
A very simple solution using the standard dict 'get' method:
d={}
for c,v in tuple_list:
d[c]=d.get(c,0)+v
Try this out:
def get_sum(tuple_list):
new_dict = {}
for tuple in tuple_list:
if tuple[0] not in new_dict:
new_dict[tuple[0]] = tuple[1]
else:
new_dict[tuple[0]] += tuple[1]
return new_dict
tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
sum_dict = get_sum(tuple_list)
for key in sorted(sum_dict.keys()):
print("{}: {}".format(key, sum_dict[key]))
If the entry is not in your list, then you make the dictionary key, value pair be the first and second indexes of the tuple. Otherwise, the key is already in the dictionary, so we simply add to its current value.

List all keys in dictionaries which are inside a list. (Dictionary in a list)

Okay, not sure how to explain this problem but here goes.
This is my dictionary myDictionary = {'12/2019' : [{'1003' : 2}, {'1040' : 3}]}
I'm trying to list out the '1003', '1040'.
I've tried using this method:
for i in range(len(a['12/2019'])):
print(a['12/2019'][i].keys())
It kind of works however it returns me
dict_keys(['1003'])
dict_keys(['1040'])
Is there anyway I can just get 1030 and 1040 to be isolated from the ... dict_keys([''])?
You can iterate over the values of the dictionary, and if the value is a list, iterate over the dictionaries in the list, and append all the keys to the result
myDictionary = {'12/2019' : [{'1003' : 2}, {'1040' : 3}],
'11/2019': '1005', '10/2019': 1234,
'09/2019': [{'1006' : 2}, {'1042' : 3}],
'08/2019': (1,2)}
keys=[]
#Iterate over values
for value in myDictionary.values():
#If value is a list
if isinstance(value, list):
#Iterate over the list
for d in value:
#Add the keys to the result
keys.extend(list(d.keys()))
print(keys)
The output will be
['1003', '1040', '1006', '1042']
You can also do this via a list-comprehension, but it's not really readable, so I would avoid against it
[key for value in myDictionary.values() if isinstance(value, list) for d in value for key in d.keys()]
Iterate over the sub-dicts in the list, grabbing the keys:
for sub_dict in a['12/2019']:
for key, val in sub_dict.items():
print(key)
You can use a list-comprehension:
[k for v in myDictionary.values() for x in v for k in x]
In code:
myDictionary = {'12/2019' : [{'1003' : 2}, {'1040' : 3}]}
print([k for v in myDictionary.values() for x in v for k in x])
# ['1003', '1040']
You could do this by doing something like this
data = {'12/2019' : [{'1003' : 2}, {'1040' : 3}]}
# Data is a dictionary of where each value corresponding
# to the key is a list of dictionaries.
for k, v in data.items():
# v is a list of dictionaries
all_keys = []
for value in v:
all_keys.extend(list(value.keys()))
print (all_keys)
The result is ['1003', '1040']
This may be more than you need, but if the data you shared for the example is just a small subset of what you're really looking at, here's a recursive function that can go as deep as you want it to.
Since you seem to want to skip the keys in the outer most level, I put in a spot to allow you to skip over the keys at a given depth. You shouldn't set the level argument manually since the code will just update that for itself.
def list_keys(element, ignore_levels=[], level=1):
"""
Recursivly list keys found in an element.
element: item to inspect.
ignore_levels: list of numeric levels to ignore.
level: recursion depth level.
"""
keys = []
# add keys if we're not ignoring this level and set iterable to values
if isinstance(element, dict):
if level not in ignore_levels:
keys.extend(element.keys())
iterable = element.values()
# if we hve a list or tuple, we can iterate over it
elif isinstance(element, (list, tuple)):
iterable = element
# if we have a single value, it's not a key and there's nothing to iterate
else:
iterable = []
# Iterate over elements and append any keys found
for i in iterable:
subkeys = list_keys(i, ignore_levels, level + 1)
if subkeys:
keys.extend(subkeys)
return keys
d = {'12/2019': [{'1003': 2}, {'1040': 3}]}
print(list_keys(d, ignore_levels=[1]))
# ['1003', '1040']

keyerror 1 in my code

I am writing a function that take dictionary input and return list of keys which have unique values in that dictionary. Consider,
ip = {1: 1, 2: 1, 3: 3}
so output should be [3] as key 3 has unique value which is not present in dict.
Now there is problem in given fuction:
def uniqueValues(aDict):
dicta = aDict
dum = 0
for key in aDict.keys():
for key1 in aDict.keys():
if key == key1:
dum = 0
else:
if aDict[key] == aDict[key1]:
if key in dicta:
dicta.pop(key)
if key1 in dicta:
dicta.pop(key1)
listop = dicta.keys()
print listop
return listop
I am getting error like:
File "main.py", line 14, in uniqueValues
if aDict[key] == aDict[key1]: KeyError: 1
Where i am doing wrong?
Your main problem is this line:
dicta = aDict
You think you're making a copy of the dictionary, but actually you still have just one dictionary, so operations on dicta also change aDict (and so, you remove values from adict, they also get removed from aDict, and so you get your KeyError).
One solution would be
dicta = aDict.copy()
(You should also give your variables clearer names to make it more obvious to yourself what you're doing)
(edit) Also, an easier way of doing what you're doing:
def iter_unique_keys(d):
values = list(d.values())
for key, value in d.iteritems():
if values.count(value) == 1:
yield key
print list(iter_unique_keys({1: 1, 2: 1, 3: 3}))
Use Counter from collections library:
from collections import Counter
ip = {
1: 1,
2: 1,
3: 3,
4: 5,
5: 1,
6: 1,
7: 9
}
# Generate a dict with the amount of occurrences of each value in 'ip' dict
count = Counter([x for x in ip.values()])
# For each item (key,value) in ip dict, we check if the amount of occurrences of its value.
# We add it to the 'results' list only if the amount of occurrences equals to 1.
results = [x for x,y in ip.items() if count[y] == 1]
# Finally, print the results list
print results
Output:
[3, 4, 7]

Categories

Resources