Removing and Converting Values of a dictionary - python

I have a dictionary with multiple values:
wd = {'A1': ('01', '10', '0001', '0010', '0100', '1000'), 'A2':('02', '20', '0002', '0020', '0200', '2000')
What I'm attempting to do is make is so if the string in the values begins with '1' or '2' that my dictionary will remove it from the dictionary so '10', '1000', '20', '2000' will be removed. Here's the code I'm trying:
remove = ('1'), ('2')
for k,v in wd.items():
for c in k:
if c.startswith(remove):
wd = {x for x in wd if x not in remove}
print(wd)
Expected Output:
wd = {'A1': ('01', '0001', '0010', '0100'), 'A2':('02', '0002', '0020', '0200')
I'm also trying to make it so if I have a string:
mystr = '0010'
That my dictionary will be able to convert that string to the key in my dictionary so '0010' will become 'A1' since the value of '0010' is paired to key 'A1'. I'm able to successfully do this with a dictionary with single key,value pairs but when it comes to multiple values I get stumped.
This is the code I'm working with:
for k,v in wd.items():
enstr = ''.join(str(wd.get(c)) for c in mystr)
print(enstr)
Output:
NoneNoneNoneNone
NoneNoneNoneNone
NoneNoneNoneNone
NoneNoneNoneNone
NoneNoneNoneNone
NoneNoneNoneNone
NoneNoneNoneNone
NoneNoneNoneNone
NoneNoneNoneNone
Expected Output when I print(enstr):
'A1'

If I get this right, you want to remove values which start with anything given by remove and further you want to group the dictionary by values.. so you want a map from a value to it's group e.g. 01 -> A1.
The following should do this:
from itertools import cycle
wd = {'A1': ('01', '10', '0001', '0010', '0100', '1000'), 'A2':('02', '20', '0002', '0020', '0200', '2000')}
remove = ('1'), ('2')
for k, values in wd.items():
wd[k] = [
value for value in values
if not any([value.startswith(r) for r in remove])
]
lists = list()
for k, v in wd.items():
lists += list(map(lambda x: x[::-1], zip(cycle([k]), v)))
print(wd)
print(dict(lists))
which gives:
{'A1': ['01', '0001', '0010', '0100'], 'A2': ['02', '0002', '0020', '0200']}
{'0001': 'A1', '0200': 'A2', '0020': 'A2', '0100': 'A1', '02': 'A2', '0010': 'A1', '0002': 'A2', '01': 'A1'}

wd = {
key: list(filter(lambda x: x[0] not in ['1', '2'], val))
for key, val in wd.items()
}

For the second part of your problem:
mystr = '0010'
wd = {'A1': ('01', '10', '0001', '0010', '0100', '1000'), 'A2':('02', '20', '0002', '0020', '0200', '2000')
for k,v in wd.items():
if mystr in v:
print(k)

Related

how to creat list compersion with 2 IFs with 3 expersions

I was struggling with syntax to convert the below code to list comprehension but no luck,
x = ['3', '15', '161', '2', '4113', '26', '1141', '00', '05', '02', '064']
c = []
for i in x:
if len(i) <= 2:
i = '00' + i
if len(i) <= 3:
i = '0' + i
c.append(i)
how to place the second condition:
['00' + i for i in x if len(i) <= 2 if len(i) <= 3]
You can define a base string and fill the base string base on the length of each item.
base = '0000'
res = [base[len(i):] + i for i in x]
# Or by thanks #Chris
# res = [f"{'0' * (4-len(i))}{i}" for i in x]
print(res)
['0003', '0015', '0161', '0002', '4113', '0026', '1141', '0000', '0005', '0002', '0064']
you can Multiplication operator *. Multiplication operator is used with strings in Python for the purpose of repetition.
for i in x:
indx = x.index(i)
x[indx] = '0'* (4-len(i)) + i
using list comprehension,
c= [ '0'* (4-len(i)) + i for i in x]
print(c)
You are never not appending a value to your new list, so you don't need filters on your list comprehension. You're just changing what you're appending.
[f'000{d}' if len(d) == 1 else \
f'00{d}' if len(d) == 2 else \
f'0{d}' if len(d) == 3 else \
d
for d in x]
# ['0003', '0015', '0161', '0002', '4113', '0026',
# '1141', '0000', '0005', '0002', '0064']
But you can simply use a format specifier in an f-string to accomplish the same.
[f'{int(d):04}' for d in x]
# ['0003', '0015', '0161', '0002', '4113', '0026',
# '1141', '0000', '0005', '0002', '0064']
Or without the intermediate conversion to an int.
[f'{d:>04}' for d in x]
# ['0003', '0015', '0161', '0002', '4113', '0026',
# '1141', '0000', '0005', '0002', '0064']
we can give some more flexibility for the numbers to pad with zeros, if we calculate the element with the most digits / characters. so if the longest element will be '4113991', the numbers will all be padded to this length:
x = ['3', '15', '161', '2', '4113991', '26', '1141', '00', '05', '02', '064']
len_ = len(max(x,key=len))
print([f"{int(num):0{len_}}" for num in x])
output: ['0000003', '0000015', '0000161', '0000002', '4113991', '0000026', ...]

How to input data from Excel to Python dictionary?

My code:
import openpyxl
workbook = openpyxl.load_workbook('master.xlsx')
worksheet = workbook.worksheets[0]
result = {}
for k, v in zip(worksheet['A'], worksheet['B']):
result[k.internal_value] = v.internal_value
print(result)
The output I get:
{'PPPPP': '22', 'bbbbb': '20', 'ccccc': '30', 'ddddd': '40', 'eeeee': '50'}
Excel file:
The output I want:
{'PPPPP': ['22','10'], 'bbbbb': ['20','30'], 'ccccc': ['30','30'], 'ddddd': '40', 'eeeee': '50'}
You can do it using pandas
import pandas as pd
df = pd.read_excel('master.xlsx', 0, None, ['A', 'B'])
result = {}
for x, y in zip(df['A'], df['B']):
if x in result:
result[x] = [result.get(x)]
result[x].append(str(y))
else:
result[x] = str(y)
print(result)
{'ppp': ['10', '22'], 'bbb': ['20', '30'], 'ccc': ['30', '30'], 'ddd': '40', 'eee': '50'}
Use a defaultdict, with an empty list as the default, and append each new value:
from collections import defauldict
import openpyxl
workbook = openpyxl.load_workbook('master.xlsx')
worksheet = workbook.worksheets[0]
result = defaultdict(list)
for k, v in zip(worksheet['A'], worksheet['B']):
result[k.internal_value].append(v.internal_value)
print(result)
Here EVERY result will be a list, even when you only have one value. e.g. you will get 'ddddd': ['40'] but you should be able to handle all key value pairs consistently.

How can I add a value in my list when a condition is true?

I have a dict with alot of items:
{'id-quantity-60': u'1', 'id-quantity-35': u'3','id-product-35': u'on', 'id-product-60': u'on',}
I need to create a list with all three elements inside.
I'm expecting a list like this:
<type 'list'>: [['60', u'1', u'on'], ['35', u'3', u'on'],]
I have only 2 values above, but 2 times the same product-id. So it should add the quantity and the 'on off' together to the same product-id.
How can I do that? I tried it with something like this:
for key, value in request.params.items():
if key[:12] == 'id-quantity-':
if key[12:] in list:
list.insert(key[12:], value)
else:
list.append([key[12:], value])
if key[:11] == 'id-product-':
if key[11:] in list:
list.insert(key[11:], value)
else:
list.append([key[11:], value])
The problem is I get this list all time splitet:
<type 'list'>: [['60', u'1'], ['35', u'3'], ['35', u'on'], ['60', u'on'],]
finally I should be able to fill the data in here (60, 1, True for example):
data = request.registry['website']._subscription_exclude_product(cr, uid, [{'product_id': int(60), 'qty': int(1), 'like': bool(True)}], context=context)
Thank you very much.
Is it what you expect?
products = {k.split('-')[-1]: v for k, v in x.items() if 'product' in k}
quantities = {k.split('-')[-1]: v for k, v in x.items() if 'quantity' in k}
all = [(k, v, 'on' if k in products else 'off') for k, v in quantities.items()]
You can use defaultdict() with a default list of 2 items to make it more flexible:
from collections import defaultdict
def default_list():
return [None, None]
request = {'id-quantity-60': u'1', 'id-quantity-71': u'0', 'id-quantity-35': u'3','id-product-35': u'on', 'id-product-60': u'on'}
result = defaultdict(default_list)
for key, value in request.items():
_, pattern, productid = key.split('-')
if pattern == 'quantity':
result[productid][0] = value
result[productid][1] = 'on' if int(value) else 'off'
elif pattern == 'product':
result[productid][1] = value
Returns:
defaultdict(<function default_list at 0x7faa3d3efe18>,
{'35': ['3', 'on'],
'60': ['1', 'on'],
'71': ['0', 'off']})
In case you really need a list:
resultList = [[k]+v for (k,v) in result.items()]
>>> [['60', '1', 'on'], ['71', '0', 'off'], ['35', '3', 'on']]
Assuming keys for quantity and product are in the same format across the dictionary:
d={'id-quantity-60': u'1', 'id-quantity-35': u'3','id-product-35': u'on', 'id-product-60': u'on',}
l=[]
for k,v in d.items():
if 'id-quantity' in k:
x = k.replace('id-quantity-','')
y = 'id-product-'+str(x)
l.append([x, v, d[y]])
print(l)
Output
[['60', '1', 'on'], ['35', '3', 'on']]
Suppose your input dictionary is in request.params variable,
quantity = {k.split("-")[-1]: v for k, v in request.params.items() if "quantity" in k}
product = {k.split("-")[-1]: v for k, v in request.params.items() if "product" in k}
result = [[k, v, product[k]] for k, v in quantity.items()]
print(result)
Output:
[['60', '1', 'on'], ['35', '3', 'on']]
Updated: replace result=... with the following
result = [[k, v, True if product.get(k) else False] for k, v in quantity.items()]
to get
[['35', '3', True], ['42', '0', False]]
if "id-product-42" is not in input dict.

Flatting list in dictionary in Python

How can I flat list in dictionary if I have something like this:
Object {'a': '48',
'b': '24',
'c':[{'cA':'20', 'cB':'42', 'cC':'55'}, {'c1':'21', 'c2':'43','c3':'58'}],
'd':'44',
'e':'32',}
That's parsed XML file, in XML C has a structure like this:
<p name = "a">48<\p>
<p name = "b">24<\p>
<list name ="C">
<item>
<cA>20<\cA>
<cB>42<\cB>
<cC>55<\cC>
<\item>
<item>
<c1>21<\c1>
<c2>43<\c2>
<c3>58<\c3>
<\item>
<\list>
<p name = "D">44<\p>
<p name = "e">32<\p>
Desired output would be :
Object {'a':'48',
'b':'24',
'cA':'20',
'cB':'42',
'cC':'55',
'c1':'21',
'c2':'43',
'c3':'58'
'd':'44',
'e':'32'}
supposing that you have fixed depth and contain "flat" dictionaries (that's a lot of "supposing", I know), you can iterate through the input dict and check for type of the values.
If value is a list, update the output dict with the items of the list, else update with the original items
d= {'a1': '48',
'b': '24',
'c':[{'cA':'20', 'cB':'42', 'cC':'55'}, {'c1':'21', 'c2':'43', 'c3':'58'}],
'd':'44',
'e':'32'}
new_d = {}
for k,v in d.items():
if isinstance(v,list):
for v1 in v:
new_d.update(v1)
else:
new_d[k] = v
result:
{'c2': '43', 'a1': '48', 'c3': '58', 'b': '24', 'cC': '55', 'd': '44', 'cA': '20', 'cB': '42', 'e': '32', 'c1': '21'}

merge to dictionaries preserving different values

I am very new to python (python 3.2) and I have been struggling with a difficult problem. I have two dictionary with listed lists:
d1 = {
'mammals': ['dog', '5', 'cat', '4', 'mouse', '4', 'bat', '3'],
'bird': ['robin', '8', 'bluejay', '6', 'goose', '5', 'cardinal', '5']
}
and
d2 = {
'mammals': ['cow', '5', 'horse', '4', 'cat', '4', 'dog', '3', 'beaver', '3'],
'bird': ['bluejay', '9', 'goose', '8', 'eagle', '8', 'robin', '7', 'duck', '6', 'cardinal', '5']
}
In each dictionary, the pair name-number (for instance, 'dog', '5') correspond to how many instances of said item where present in the original data bases.
What I need is to merge the two dictionaries in a way that information about quantity preserved (again, in the example, the new dictionary would have 'dog', '5', '3'. So that the merged dictionary would look somewhat like (I am not necessarily committed to nested dictionaries. I wrote it this way for easiness of visualization. The important thing is too keep the information):
d_merged = {
'mammals': [{'dog': ['5', '3']}, {'cat': ['4', '4']}, {'mouse': '4'}, {'bat': '3'} , {'cow': '5'},
{'horse': '4'}, {'beaver': '3'}],
'bird': [{'robin': ['8', '7']}, {'bluejay': ['6', '9']}, {'goose': ['5','8']}, {'cardinal': ['5',
'5']}, {'eagle': '8'}, {'duck', '6'}]
}
I have tried various things with tuples, nested dictionaries and other possibilities, but the result has been a mess. It would mean a lot if someone could point me in a good direction to solve this. I thank you very much
The most readable way to do it is probably as follows:
output = {}
for key in d1.keys():
output[key] = {}
lst = d1[key]
for name, count in (lst[i:i+2] for i in range(0, len(lst), 2)):
output[key][name] = (int(count),)
for key in d2.keys():
if key not in output:
output[key] = {}
lst = d2[key]
for name, count in (lst[i:i+2] for i in range(0, len(lst), 2)):
if name in output[key].keys():
output[key][name] += (int(count),)
else:
output[key][name] = (int(count),)
In incomprehensible dictionary comprehensions, you can do it in two steps
d = {k: {a: int(b) for a, b in (v[i:i+2] for i in range(0, len(v), 2))}
for k, v in d.items()}
To turn them into dictionaries of dictionaries, e.g.
{'mammals': {'cat': 4, 'cow': 5, 'dog': 3, 'beaver': 3, 'horse': 4},
'bird': {'goose': 8, 'duck': 6, 'eagle': 8, 'bluejay': 9, 'robin': 7, 'cardinal': 5}}
Then
output = {k1: {k2: (d1.get(k1, {}).get(k2), d2.get(k1, {}).get(k2))
for k2 in set(list(d1.get(k1, {}).keys()) + list(d2.get(k1, {}).keys()))}
for k1 in set(list(d1.keys()) + list(d2.keys()))}
To combine the two.
Note that these methods both work even if there are different keys at the two levels (e.g. adding d1['reptiles'] = {'lizard': 10}).
first you can change d1 and d2 to be dictionaries that is easier to work with:
[note that list[::2] is sublist that holds all the item in the even indices, and list[1::2] holds the odds.]
>>> dc1 = {}
>>> for family in d1.keys():
l = d1[family]
dc1[family] = {l[::2][family]:[l[1::2][family]] for family in range(len(l)/2)}
>>> dc2 = {}
>>> for family in d1.keys():
l = d2[family]
dc2[family] = {l[::2][family]:[l[1::2][family]] for family in range(len(l)/2)}
now dc1 and dc2 are these:
>>> dc1
{'mammals': {'bat': ['3'], 'mouse': ['4'], 'dog': ['5'], 'cat': ['4']},
'bird': {'goose': ['5'], 'cardinal': ['5'], 'robin': ['8'], 'bluejay': ['6']}}
>>> dc2
{'mammals': {'beaver': ['3'], 'horse': ['4'], 'dog': ['3'], 'cow': ['5'], 'cat': ['4']},
'bird': {'eagle': ['8'], 'bluejay': ['9'], 'goose': ['8'], 'cardinal': ['5'], 'duck': ['6'], 'robin': ['7']}}
and then you just need to combine them
>>> d_merged = {}
>>> families = set(d1.keys()+d2.keys())
>>> family2animals = {family:list(set(dc1[family].keys()+dc2[family].keys())) for family in families}
>>> for family in families:
d_merged[family] = [{animal:dc1[family].get(animal,[])+dc2[family].get(animal,[])} for animal in family2animals[family]]

Categories

Resources