creating multiple lists from a master nested list - python

I have a nested list that I got from data that will be broken into sections to be uploaded to a database but have to be separate entries.
My nested list:
Master_List = [ a, [1,2,3], [1,2], d]
But I need to make it into six separate lists such as this:
list1 = [a, 1, 1, d]
list2 = [a, 1, 2, d]
list3 = [a, 2, 1, d]
list4 = [a, 2, 2, d]
etc.
I've tried iterating through the lists through the values of the list, but I'm confused since not all the master list indices will have more than one value. How do can I build these separate lists to be used?
When I tried just iterating through the lists and creating separate lists it became a convoluted mess.
Edit: Coldspeed's solution is exactly what I needed. Now I just use the dictionary to access the list I want.

The easiest way to do this would be using itertools.product.
from itertools import product
out = {'list{}'.format(i) : list(l) for i, l in enumerate(product(*Master_List), 1)}
print(out)
{'list1': ['a', 1, 1, 'd'],
'list2': ['a', 1, 2, 'd'],
'list3': ['a', 2, 1, 'd'],
'list4': ['a', 2, 2, 'd'],
'list5': ['a', 3, 1, 'd'],
'list6': ['a', 3, 2, 'd']}
Unfortunately, you cannot create a variable number of variables without the use of a dictionary. If you want to access listX, you'll access the out dictionary, like this:
out['listX']

A one-liner would be:
lists = sum([[[Master_List[0], i, j, Master_List[3]] for i in Master_List[1]] for j in Master_List[2]], [])

Related

Extending lists of lists [duplicate]

This question already has answers here:
Why do these list operations (methods: clear / extend / reverse / append / sort / remove) return None, rather than the resulting list?
(6 answers)
How do I iterate through two lists in parallel?
(8 answers)
How do I concatenate two lists in Python?
(31 answers)
Closed 6 months ago.
I'm trying to extend two lists of lists in python, so that item 1 of the first list of lists extends with item 1 of the second list of lists, and so forth.
I'm new to this and self-taught, so could be missing something very simple, but I can't find an answer anywhere.
This is what I feel the code should be, but obviously not working.
list1[x].extend(list2[x]) for x in list1
What I'm trying to achieve is this:
list1 = [[1,2,3],[4,5,6],[7,8,9]]
list2 = [[a,b,c],[d,e,f],[g,h,i]]
output = [[1,2,3,a,b,c],[4,5,6,d,e,f],[7,8,9,g,h,i]]
Any ideas?
You can use zip:
list1 = [[1,2,3],[4,5,6],[7,8,9]]
list2 = [['a','b','c'], ['d','e','f'], ['g','h','i']]
output = [sub1 + sub2 for sub1, sub2 in zip(list1, list2)]
print(output)
# [[1, 2, 3, 'a', 'b', 'c'], [4, 5, 6, 'd', 'e', 'f'], [7, 8, 9, 'g', 'h', 'i']]
Use zip() to loop over the two lists in parallel. Then use extend() to append the sublist from list2 to the corresponding sublist in list1.
for l1, l2 in zip(list1, list2):
l1.extend(l2)
print(list1)
list1[x].extend(list2[x]) does achieve the result you want for one pair of lists, if list1[x] is [1, 2, 3] and list2[x] is [a, b, c], for example.
That means x has to be an index:
x = 0
list1[x].extend(list2[x])
# now the first list in `list1` looks like your desired output
To do that for every pair of lists, loop over all possible indexes x – range(upper) is the range of integers from 0 (inclusive) to upper (exclusive):
for x in range(len(list1)):
list1[x].extend(list2[x])
# now `list1` contains your output
To produce a new list of lists instead of altering the lists in list1, you can concatenate lists with the + operator instead:
>>> [1, 2, 3] + ['a', 'b', 'c']
[1, 2, 3, 'a', 'b', 'c']
output = []
for x in range(len(list1)):
output.append(list1[x] + list2[x])
And finally, the idiomatic Python for this that you’ll get around to someday is:
output = [x1 + x2 for x1, x2 in zip(list1, list2)]
I have simply used list comprehension with list addition, while zipping the correlated lists together
list1 = [[1,2,3],[4,5,6],[7,8,9]]
list2 = [['a','b','c'], ['d','e','f'], ['g','h','i']]
list3 = [l1+l2 for l1, l2 in zip(list1, list2)]
print(list3)
[[1, 2, 3, 'a', 'b', 'c'], [4, 5, 6, 'd', 'e', 'f'], [7, 8, 9, 'g', 'h', 'i']]

How to replace values of a list with values of another list based on index

I am wondering if I can replace values of a list with elements of another list based on the index in Python:
let's say
a=[3, 2, 8, 7, 0]
d=['a','b','c','d','e','f','g','h','i']
I want to replace the elements of list a with the elements of list d. Values of list a define the index number of list d.
I want a list like c,
c=['d','c','i','a']
a = [3,2,8,7,0]
b = ['a','b','c','d','e','f','g','h','i']
l = [b[i] for i in a]
# d, c, i, a
Use __getitem__ with map which is quite faster.
list(map(d.__getitem__, a))
Output >> ['d', 'c', 'i', 'h', 'a']
a=[3, 2, 8, 7, 0]
d=['a','b','c','d','e','f','g','h','i']
d = np.array(d)
d[[a]]
This can be done with the help of numpy.
I would do it in this manner: (anyway I am curious if there is another, simplest way)
c=[]
a=[3, 2, 8, 7, 0]
d=['a','b','c','d','e','f','g','h','i']
for index in a:
c.append(d[index])
print(c)
result: c = ['d', 'c', 'i', 'h', 'a']

calculate sum of all unique elements in a list based on another list python

I have two lists like this,
a=[['a', 'b', 'c'], ['b', 'c'], ['a', 'd'], ['x']]
b=[[1, 2, 3], [4,5], [6,7], [8]] (the size of a and b is always same)
Now I want to create two list with the sum of unique elements, so the final lists should look like,
a=['a', 'b', 'c', 'd', 'x']
b=[7, 6, 8, 7, 8] (sum of all a, b, d, d and x)
I could do this using for loop but looking for some efficient way to reduce execution time.
Not so pythonic but will do the job:
a=[['a', 'b', 'c'], ['b', 'c'], ['a', 'd'], ['x']]
b=[[1, 2, 3], [4,5], [6,7], [8]]
mapn = dict()
for elt1, elt2 in zip(a, b):
for e1, e2 in zip(elt1, elt2):
mapn[e1] = mapn.get(e1, 0) + e2
elts = mapn.keys()
counts = mapn.values()
print(mapn)
print(elts)
print(counts)
You can use zip and collections.Counter along the following lines:
from collections import Counter
c = Counter()
for la, lb in zip(a, b):
for xa, xb in zip(la, lb):
c[xa] += xb
list(c.keys())
# ['a', 'b', 'c', 'd', 'x']
list(c.values())
# [7, 6, 8, 7, 8]
Here some ideas.
First, to flatten your list you can try:
a=[['a', 'b', 'c'], ['b', 'c'], ['a', 'd'], ['x']]
b=[[1, 2, 3], [4,5], [6,7], [8]]
To have uniques elements, you can do something like
A = set([item for sublist in a for item in sublist])
But what I would do first (perhaps not the more efficient) is :
import pandas as pd
import bumpy as np
LIST1 = [item for sublist in a for item in sublist]
LIST2 = [item for sublist in b for item in sublist]
df = pd.DataFrame({'a':LIST1,'b':LIST2})
df.groupby(df.a).sum()
OUTPUT:
At the end of the day, you're going to have to use two for loops. I have a one liner solution using zip and Counter.
The first solutions works only in this specific case where all the strings are a single character, because it creates a string with the right number of each letter, and then gets the frequency of each letter.
from collections import Counter
a = [['a', 'b', 'c'], ['b', 'c'], ['a', 'd'], ['x']]
b = [[1, 2, 3], [4,5], [6,7], [8]]
a, b = zip(*Counter(''.join(x*y for al, bl in zip(a, b) for x, y in zip(al, bl))).items())
For the more general case, you can do:
a, b = zip(*Counter(dict(p for al, bl in zip(a, b) for p in zip(al, bl))).items())
You can combine the lists and their internal lists using zip(), then feed the list of tuples to a dictionary constructor to get a list of dictionaries with values for each letter. Then convert those dictionaries to Counter and add them up.
a = [['a', 'b', 'c'], ['b', 'c'], ['a', 'd'], ['x']]
b = [[ 1, 2, 3 ], [ 4, 5 ], [ 6, 7 ], [ 8 ]]
from collections import Counter
from itertools import starmap
mapn = sum(map(Counter,map(dict,starmap(zip,zip(a,b)))),Counter())
elts,counts = map(list,zip(*mapn.items()))
print(mapn) # Counter({'c': 8, 'x': 8, 'a': 7, 'd': 7, 'b': 6})
print(elts) # ['a', 'b', 'c', 'd', 'x']
print(counts) # [ 7, 6, 8, 7, 8]
detailed explanation:
zip(a,b) combines the lists into pairs of sublists. e.g. (['a','b','c'],[1,2,3]), ...
starmap(zip,...) takes these list pairs and merges then together into sublist of letter-number pairs: [('a',1),('b',2),('c',3)], ...
Each of these lists of pairs is converted to a dictionary by map(dict,...) and then into a Counter object by map(counter,...)
We end up with a list of Counter objects corresponding to the pairing of each sublist. Applying sum(...,Counter()) computes the totals for each letter into a single Counter object.
Apart from being a Counter object, mapn is excatly the same as the dictionary that you produced.

Merge two or more lists with given order of merging

On start I have 2 lists and 1 list that says in what order I should merge those two lists.
For example I have first list equal to [a, b, c] and second list equal to [d, e] and 'merging' list equal to [0, 1, 0, 0, 1].
That means: to make merged list first I need to take element from first list, then second, then first, then first, then second... And I end up with [a, d, b, c, e].
To solve this I just used for loop and two "pointers", but I was wondering if I can do this task more pythonic... I tried to find some functions that could help me, but no real result.
You could create iterators from those lists, loop through the ordering list, and call next on one of the iterators:
i1 = iter(['a', 'b', 'c'])
i2 = iter(['d', 'e'])
# Select the iterator to advance: `i2` if `x` == 1, `i1` otherwise
print([next(i2 if x else i1) for x in [0, 1, 0, 0, 1]]) # ['a', 'd', 'b', 'c', 'e']
It's possible to generalize this solution to any number of lists as shown below
def ordered_merge(lists, selector):
its = [iter(l) for l in lists]
for i in selector:
yield next(its[i])
In [4]: list(ordered_merge([[3, 4], [1, 5], [2, 6]], [1, 2, 0, 0, 1, 2]))
Out[4]: [1, 2, 3, 4, 5, 6]
If the ordering list contains strings, floats, or any other objects that can't be used as list indexes, use a dictionary:
def ordered_merge(mapping, selector):
its = {k: iter(v) for k, v in mapping.items()}
for i in selector:
yield next(its[i])
In [6]: mapping = {'A': [3, 4], 'B': [1, 5], 'C': [2, 6]}
In [7]: list(ordered_merge(mapping, ['B', 'C', 'A', 'A', 'B', 'C']))
Out[7]: [1, 2, 3, 4, 5, 6]
Of course, you can use integers as dictionary keys as well.
Alternatively, you could remove elements from the left side of each of the original lists one by one and add them to the resulting list. Quick example:
In [8]: A = ['a', 'b', 'c']
...: B = ['d', 'e']
...: selector = [0, 1, 0, 0, 1]
...:
In [9]: [B.pop(0) if x else A.pop(0) for x in selector]
Out[9]: ['a', 'd', 'b', 'c', 'e']
I would expect the first approach to be more efficient (list.pop(0) is slow).
How about this,
list1 = ['a', 'b', 'c']
list2 = ['d', 'e']
options = [0,1,0,0,1]
list1_iterator = iter(list1)
list2_iterator = iter(list2)
new_list = [next(list2_iterator) if option else next(list1_iterator) for option in options]
print(new_list)
# Output
['a', 'd', 'b', 'c', 'e']

Python - dictionary of lists

Which is the best way to make a dictionary of lists?
For instance, if I have lists list1, list2 and want to make a dictionary my_dict like that:
my_dict = ['list1': list1, 'list2': list2]
I've found this example but the best answer is written in 2009. Maybe there are some new more laconic ways to do this?
You need to use curly rather than square brackets, but otherwise this is probably as good as it gets:
list1 = ['a', 'b', 'c']
list2 = [1, 2, 3, 4]
my_dict = {'list1': list1, 'list2': list2}
For a dictionary of lists, consider a defaultdict.
A normal dictionary works fine, but it raises an error if a key is not found.
list1 = list("abcd")
list2 = [1, 2, 3, 4]
d = {"list1": list1, "list2": list2}
d["list3"]
# KeyError: 'list3'
This may be disruptive in some applications and may require additional exception handling.
The defaultdict behaves like a normal dict while adding some protection against errors.
import collections as ct
dd = ct.defaultdict(list)
dd.update(d)
dd
# defaultdict(list, {'list1': ['a', 'b', 'c', 'd'], 'list2': [1, 2, 3, 4]})
Adding a missing key will call the default factory function, i.e. list. Here instead of a error, we get an empty container:
dd["list3"]
# []
This entry was added with an empty list.
dd
# defaultdict(list,
# {'list1': ['a', 'b', 'c', 'd'],
# 'list2': [1, 2, 3, 4],
# 'list3': []})
Convert a defaultdict to a regular dict by setting the default factory to None
dd.default_factory = None
dd
# defaultdict(None, {'list1': ['a', 'b', 'c', 'd'], 'list2': [1, 2, 3, 4]})
or by using the dict() builtin:
dict(dd)
# {'list1': ['a', 'b', 'c', 'd'], 'list2': [1, 2, 3, 4]}
If you want to turn the variable name into a key, here is a similar question.
If you just want a dictionary of lists with a sequential key.
def turn_to_dict(*args):
return {i: v for i, v in enumerate(args)}
lst1 = [1, 2, 3, 4]
lst2 = [3, 4, 6, 7]
lst3 = [5, 8, 9]
v = turn_to_dict(lst1, lst2, lst3)
>>> print(v)
{0: [1, 2, 3, 4], 1: [3, 4, 6, 7], 2: [5, 8, 9]}
Try this method, very succinct. Curly braces, not square brackets.
I think that's the shortest way around it.
list1 = [5, 500, 543]
list2 = [4, 4, 4]
my_dict = {'list1':list1, 'list2': list2}
This should work:
my_dict = dict([('list1', list1), ('list2', list2)])
Or, alternatively:
my_dict = {'list1': list1, 'list2': list2}
The result will be the same.
Use the curly brace syntax to define the dictionary, and give each entry in your dictionary a key that corresponds to each value:
list_a = [1,2,3,4,5]
list_b = [6,7,8,9,10]
my_dict = {'list1':list_a, 'list2':list_b}
More in the python docs

Categories

Resources