I have two lists that I wanted to merge:
list1 = [['desktop', '10022'], ['mobile', '119'], ['tablet', '7']]
list2 = [['desktop', '9964'], ['mobile', '117'], ['tablet', '8']]
I wanted to arrange them into this list:
new_list = [('desktop', ['10022', '9964']), ('mobile', ['119', '117']), ('tablet', ['7', '8'])]
then, I also wanted to compute the percentage difference between the integers and insert the answer in the list:
updated_list = [['desktop', '10022', '9964', '0.5821'], ['mobile', '119', '117', '1.7094'], ['tablet', '7', '8', '-12.5']]
Here's my rough code:
from collections import OrderedDict
list1 = [['desktop', '10022'], ['mobile', '119'], ['tablet', '7']]
list2 = [['desktop', '9964'], ['mobile', '117'], ['tablet', '8']]
merged = OrderedDict()
for list_ in list1, list2:
for k, v in list_:
try:
merged[k].append(v)
except:
merged[k] = [v]
def diff(x, y):
return ((x/y)-1)*100
updated_list = [[row,x,y,diff(x,y) for x,y in vals.items()] for row,vals in merged.items()]
Can't get this thing to work :(
Assuming that your lists is sorted and homogeneous, you can
[[k, int(v1), int(v2), int(v1)/int(v2) - 1] for ((k, v1), (_, v2)) in zip(list1, list2)]
If lists data is homogeneous, but not sorted, simply call
list1.sort()
list2.sort()
prior to processing it. If data is not homogeneous, simple way to iterate over is to cast lists to dictionaries and iterate over common keys:
d1, d2 = dict(list1), dict(list2)
[[k, int(d1[k]), int(d2[k]), int(d1[k])/int(d2[k]) -1] for k in d1.keys() & d2.keys()]
Here is a working code:
# The same, and then
updated_list = [(row, vals[0], vals[1], diff(int(vals[0]), int(vals[1]))) for row, vals in merged.items()]
print(updated_list)
Your problem was that you wanted to unpack x and y from vals, but you can't do that unless vals is a list of tuples.
In
updated_list = [[row,x,y,diff(x,y) for x,y in vals.items()] for row,vals in merged.items()]
vals is a list, so it has no method items(), the inner list-comprehension has a syntax error and would not work even if it were [(row,x,y,diff(x,y) )for x,y in vals.items()] or some such, because of the wrong method call. Also you wouldn't unpack a list of 2 with for x,y in vals. You'd unpack a list of 2-tuples like that, for example.
This'll deviate from what you've tried, but you could create an ordered default dict, merge, and do your calculations:
In [1]: from collections import OrderedDict
In [2]: class OrderedDefaultDict(OrderedDict):
...: def __missing__(self, key):
...: obj = self[key] = self.default_factory()
...: return obj
...: def __init__(self, default_factory, *args, **kwgs):
...: super().__init__(*args, **kwgs)
...: self.default_factory = default_factory
...:
In [11]: list1 = [['desktop', '10022'], ['mobile', '119'], ['tablet', '7']]
In [12]: list2 = [['desktop', '9964'], ['mobile', '117'], ['tablet', '8']]
In [14]: merged = OrderedDefaultDict(list)
In [16]: from itertools import chain
In [17]: for k, v in chain(list1, list2):
...: merged[k].append(v)
...:
In [18]: merged
Out[18]: OrderedDefaultDict([('desktop', ['10022', '9964']), ('mobile', ['119', '117']), ('tablet', ['7', '8'])])
In [19]: def diff(x, y):
....: return ((x/y)-1)*100
....:
In [20]: [[k, x, y, str(diff(float(x), float(y)))]
...: for k, (x, y) in merged.items()]
Out[20]:
[['desktop', '10022', '9964', '0.5820955439582498'],
['mobile', '119', '117', '1.7094017094017033'],
['tablet', '7', '8', '-12.5']]
Or format the floats as you see fit, for example
'{:.4f}'.format(diff(...))
Related
I want to sort lists as the following:
input:
mylist = [['12','25'],['4','7'],['12','14']]
output:
[['4','7'],['12','14'],['12','25']]
the current code that I use only sorts the first number of the lists:
def defe(e):
return int(e[0])
mylist = [['12','25'],['4','7'],['12','14']]
mylist.sort(key=defe)
print(mylist)
output:
[['4','7'],['12','25'],['12','14']]
Try:
sorted(mylist, key=lambda x: (int(x[0]), int(x[1])))
Output:
[['4', '7'], ['12', '14'], ['12', '25']]
If sublists are longer than 2, then
sorted(mylist, key=lambda x: list(map(int, x)))
is better.
Having multiple lists and I would like to create a nested dictionary from them:
x = ['a','b','c','d']
keys_a = ['1','2','3','4']
values_a = [11,22,33,44]
keys_b = ['5','6','7','8']
values_b = [55,66,77,88]
keys_c = ['9','10','11','12']
values_c = [99,1010,1111,1212]
keys_d = ['13','14','15','16']
values_d = [1313,1414,1515,1616]
What I want to do is match a with keys_a and values_a, match b with keys_b and values_b, and c with keys_c and values_c, etc.
The expected output is the following:
d = {'a':{'1':11,
'2':22,
'3':33,
'4':44},
'b':{'5':55,
'6':66,
'7':77,
'8':88},
'c':{'9':99,
'10':1010,
'11':1111,
'12':1212,
'13':1313},
'd':{'14':1414,
'15':1515,
'16':1616,
'17':1717}}
Could you please help me to achieve this using python, I have tried with zip function but it doesn't give me the expected results. Is there any suggestions for the code I should write to have the expected output ?
Thank you !
If you're comfortable with list and dictionary comprehension, you can zip up x with a lists of your key lists and values lists. That looks like this:
output = {
a: dict(zip(k, v))
for a, k, v in zip(
x,
[keys_a, keys_b, keys_c, keys_d],
[values_a, values_b, values_c, values_d]
)}
If that's a hard read (it is), you can use a more traditional for-loop like this:
output = {}
keys = [keys_a, keys_b, keys_c, keys_d]
values = [values_a, values_b, values_c, values_d]
for a, k, v in zip(x, keys, values):
output[a] = dict(zip(k, v))
You can use the following code that uses the exec built-in function:
x = ['a', 'b', 'c', 'd']
keys_a = ['1', '2', '3', '4']
values_a = [11, 22, 33, 44]
keys_b = ['5', '6', '7', '8']
values_b = [55, 66, 77, 88]
keys_c = ['9', '10', '11', '12']
values_c = [99, 1010, 1111, 1212]
keys_d = ['13', '14', '15', '16']
values_d = [1313, 1414, 1515, 1616]
d = {}
for val in x:
c = {}
exec(f"""\
for key, val in zip(keys_{val}, values_{val}):
c[key] = val
""")
d[val] = c
print(d)
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.
I have two lists which I want to group on the basis of the first element of the lists.
list1 = [['1','abc','zef'],['2','qwerty','opo'],['3','lol','pop']]
list2 = [['1','rofl','pole'],['2','sole','pop'],['3','lmao','wtf']]
Here the first elements in the list inside the list are '1' , '2' and '3'.
I want my final list to be like :-
Final_List = [['1', 'abc', 'zef', 'rofl', 'pole'], ['3', 'lol', 'pop', 'lmao', 'wtf'], ['2', 'qwerty', 'opo', 'sole', 'pop']]
I have tried this using below code.
#!/usr/bin/python
list1 = [['1','abc','zef'],['2','qwerty','opo'],['3','lol','pop']]
list2 = [['1','rofl','pole'],['2','sole','pop'],['3','lmao','wtf']]
d = {}
for i in list1:
d[i[0]] = i[1:]
for i in list2:
d[i[0]].extend(i[1:])
Final_List = []
for key, value in d.iteritems():
value.insert(0,key)
Final_List.append(value)
This code works but i was wondering if there was an easy and cleaner way to do it
Any help?
I would have written like you have written with a little modification, like this
Prepare a dictionary with all the elements from the second position gathered corresponding to the first element.
d = {}
for items in (list1, list2):
for item in items:
d.setdefault(item[0], [item[0]]).extend(item[1:])
And then just get all the values from the dictionary (Thanks #jamylak) :-)
print(d.values())
Output
[['3', 'lol', 'pop', 'lmao', 'wtf'],
['1', 'abc', 'zef', 'rofl', 'pole'],
['2', 'qwerty', 'opo', 'sole', 'pop']]
If item sequence in the lists inside of the Final_List is not important then this can be used,
[list(set(sum(itm, []))) for itm in zip(list1, list2)]
Your code seems correct. Just modify the following portion:
Final_List = []
for key in d:
L = [key] + [x for x in d[key]]
Final_List.append(L)
Yes, with list comprehension and enumerate
list1 = [['1','abc','zef'],['2','qwerty','opo'],['3','lol','pop']]
list2 = [['1','rofl','pole'],['2','sole','pop'],['3','lmao','wtf']]
print [set(v + list2[k]) for k,v in enumerate(list1)]
[['1', 'abc', 'zef', 'rofl', 'pole'], ['2', 'qwerty', 'opo', 'sole', 'pop'], ['3', 'lol', 'pop', 'lmao', 'wtf']]
EDIT
With index relation
list1 = [['1','abc','zef'],['2','qwerty','opo'],['3','lol','pop']]
list2 = [['1','rofl','pole'],['3','lmao','wtf'],['2','sole','pop']]
d1 = {a[0]:a for a in list1}
d2 = {a[0]:a for a in list2}
print [set(v + d2[k]) for k, v in d1.items()]
Using default dict and list comprehensions you can shorten your code
from collections import defaultdict
list1 = [['1','abc','zef'],['2','qwerty','opo'],['3','lol','pop']]
list2 = [['1','rofl','pole'],['2','sole','pop'],['3','lmao','wtf']]
d = defaultdict(list)
for i in list1 + list2:
d[i[0]].extend(i[1:])
Final_List = [[key] + value for key, value in d.iteritems()]
print Final_List
list3 = []
for i in xrange(0,max(len(list1[0]), len(list2[0]))):
list3.append(list(list1[i]))
list3[i].extend(x for x in list2[i] if x not in list3[i])
with a xrange, you can iterate only once through the list.
A bit of functional style:
import operator, itertools
from pprint import pprint
one = [['1','abc','zef'],['2','qwerty','opo'],['3','lol','pop']]
two = [['1','rofl','pole'],['2','sole','pop'],['3','lmao','wtf']]
A few helpers:
zero = operator.itemgetter(0)
all_but_the_first = operator.itemgetter(slice(1, None))
data = (one, two)
def foo(group):
# group is (key, iterator) from itertools.groupby
key = group[0]
lists = group[1]
result = list(key)
for item in lists:
result.extend(all_but_the_first(item))
return result
Function to process the daa
def process(data, func = foo):
# concatenate all the sublists
new = itertools.chain(*data)
# group by item zero
three = sorted(new, key = zero)
groups = itertools.groupby(three, zero)
# iterator that builds the new lists
return itertools.imap(foo, groups)
Usage
>>> pprint(list(process(data)))
[['1', 'abc', 'zef', 'rofl', 'pole'],
['2', 'qwerty', 'opo', 'sole', 'pop'],
['3', 'lol', 'pop', 'lmao', 'wtf']]
>>>
>>> for thing in process(data):
print thing
['1', 'abc', 'zef', 'rofl', 'pole']
['2', 'qwerty', 'opo', 'sole', 'pop']
['3', 'lol', 'pop', 'lmao', 'wtf']
>>>
list1 = [['1','abc','zef'],['2','qwerty','opo'],['3','lol','pop']]
list2 = [['1','rofl','pole'],['2','sole','pop'],['3','lmao','wtf']]
Final_List = []
for i in range(0, len(list1)):
Final_List.append(list1[i] + list2[i])
del Final_List[i][3]
print Final_List
Output
[['1', 'abc', 'zef', 'rofl', 'pole'], ['2', 'qwerty', 'opo', 'sole', 'pop'], ['3', 'lol', 'pop', 'lmao', 'wtf']]
I am looking for a different way to get a string list from a tuple of tuples. This is how I do right now:
x = (('a',1), (2,3), (4,), (), (None,))
op_list = []
for item in x:
if item and item[0]:
op_list.append(str(item[0]))
print op_list
Output: ['a', '2', '4']
I cannot think of any other way to get to the list. My question is, is there any better/alternate/pretty way of doing this?
EDIT: Added a few pitfall inputs to the input, like an empty tuple, tuple with None and given the expected output as well. Also edited the question to ensure that I need only a list of strings irrespective of any other data type other than None.
>>> x = (('a',1), (2,3), (4,))
>>> [str(item[0]) for item in x if item and item[0]]
['a', '2', '4']
Maybe using map and lambda functions gives you the easiest and more compact way to do it:
>>> x = (('a',1), (2,3), (4,), (None,), ())
>>> filter(None, map(lambda i: str(i[0]) if len(i) > 0 and i[0] != None else None, x))
['a', '2', '4']
Use itemgetter.
from operator import itemgetter
f = itemgetter(0)
def func(i):
if not i:
return None
r = f(i)
if r:
return str(r)
Using it:
>>> x = (('a',1), (2,3), (4,), None, '', False, [], (None,), ())
>>> filter(None, map(func, x))
['a', '2', '4']
You can make it into a function:
def extract_first_non_none(collection):
return filter(None, map(func, collection))
Or into a class:
class Extractor():
def __init__(self, index):
self.getter = itemgetter(index)
def _func(self, item):
if not item:
return None
r = self.getter(item)
if r != None:
return str(r)
def extract(self, collection):
return filter(None, map(self._func, collection))
Using the class:
>>> x = (('a',1), (2,3), (4,), None, '', False, [], (None,), ())
>>> e = Extractor(0)
>>> e.extract(x)
['a', '2', '4']