I want to combine a nested list (lists in it have different lengths) into one. I would like to add by index first. Then sort by size.
Example:
lsts = [
[7, 23, 5, 2],
[3, 8, 1],
[99, 23, 9, 23, 74]
]
merged = [3, 7, 99, 8, 23, 23, 1, 5, 9, 2, 23, 74]
I would like to solve this without importing.
Assuming your list-of-lists cannot contain Nones, you can do this with itertools.zip_longest:
from itertools import zip_longest
result = []
for row in zip_longest(*lsts):
row = (x for x in row if x is not None)
for x in sorted(row):
result.append(x)
print(result)
Here is a one-liner:
import functools
import itertools
functools.reduce(lambda x,y: x+y, [sorted(x for x in p if x is not None) for p in itertools.zip_longest(*lsts)])
Output:
[3, 7, 99, 8, 23, 23, 1, 5, 9, 2, 23, 74]
I'll explain the solution step-by-step with each building on the result of the previous step.
To group items from each list by their indexes, itertools.zip_longest() is the tool for that:
>>> import itertools as it
>>> MISSING = object() # a sentinel
>>> lsts = [
[7, 23, 5, 2],
[3, 8, 1],
[99, 23, 9, 23, 74]
]
>>> it.zip_longest(*lsts, fillvalue=MISSING)
>>> list(_)
[(7, 3, 99), (23, 8, 23), (5, 1, 9), (2, <object object at 0x7f529e9b4260>, 23), (<object object at 0x7f529e9b4260>, <object object at 0x7f529e9b4260>, 74)]
This groups list elements into n-tuples using the MISSING fill value where needed, because lists might not be of equal length.
The next step is to iterate over each n-tuple and sort it internally (while skipping the MISSING values). The built-in function sorted() comes handy here:
>>> list(
sorted(x for x in ntuple if x is not MISSING)
for ntuple in it.zip_longest(*lsts, fillvalue=MISSING)
)
[[3, 7, 99], [8, 23, 23], [1, 5, 9], [2, 23], [74]]
The final step is to flatten this sequence of lists, and we'll use itertools.chain,from_iterable():
>>> list(it.chain.from_iterable(
sorted(x for x in ntuple if x is not MISSING)
for ntuple in it.zip_longest(*lsts, fillvalue=MISSING)
))
[3, 7, 99, 8, 23, 23, 1, 5, 9, 2, 23, 74]
The good thing about chain.from_iterable() is that it doesn't repeatedly concatenate smaller lists into the longer and longer final list, making it efficient. It also does this at the C level, AFAIK.
It's worth noting that None can also be used instead of the MISSING sentinel, but I used MISSING to also demonstrate how fillvalue works (e.g. you might want to use a zero instead or something else, if you wish).
zip_longest makes the work. The rest is cleaning/formatting
In [1]: from itertools import zip_longest, chain
In [2]: lsts = [
...: [7, 23, 5, 2],
...: [3, 8, 1],
...: [99, 23, 9, 23, 74]
...: ]
In [3]: [v for v in chain.from_iterable(zip_longest(*lsts)) if v !=None]
Out[3]: [7, 3, 99, 23, 8, 23, 5, 1, 9, 2, 23, 74]
Related
I have two lists, I want to sort the first one so I get them in ascending order, but I need the second list elements to be sorted with the element of the other list which they originally corresponded and I have no clue how to do that. Example:
Original imput:
l1 = [13, 1, 31, 6, 42, 99]
l2 = [14, 5, 11 ,7, 15, 12]
l1.sort()
Expected Result:
l1 = [1, 6, 13, 31, 42, 99]
l2 = [5, 7, 14 ,11, 15, 12]
Pack them in a tuple and sort it, then unpack as needed:
t = tuple(zip(l1, l2))
l_sorted = sorted(t, key=lambda e: e[0])
l1 = [e[0] for e in l_sorted]
l2 = [e[1] for e in l_sorted]
You can use sorted.
def sort_list(list1, list2):
zipped_pairs = zip(list2, list1)
j=sorted(zipped_pairs)
z = [x for _, x in j]
m = [__ for __, y in j]
print(z,m)
l1 = [13, 1, 31, 6, 42, 99]
l2 = [14, 5, 11 ,7, 15, 12]
print(sort_list(l1, l2))
Its faster if you can use numpy arrays. For example
import numpy as np
arr1 = np.array([13, 1, 31, 6, 42, 99])
arr2 = np.array([14, 5, 11 ,7, 15, 12])
arr1_sorted = np.sort(arr1)
arr2_sorted = arr2[arr1.argsort()]
# The expected answer would be
# arr1_sorted = array([1, 6, 13, 31, 42, 99])
# arr2_sorted = array([5, 7, 14 ,11, 15, 12])
Here sort() returns the sorted array, while argsort() returns the index corresponding to a sorted array
Unlikely to be fastest solution, but beautiful to my eye :)
l1 = [13, 1, 31, 6, 42, 99]
l2 = [14, 5, 11 ,7, 15, 12]
def delegated_sort(l1, l2):
return map(list, zip(*sorted(zip(l1, l2))))
>>> delegated_sort(l1, l2)
[[1, 6, 13, 31, 42, 99], [5, 7, 14, 11, 15, 12]]`
What I am doing is creating a function that returns a list containing every number in a list of bases raised to every number in a list of powers. So, using a nested for loop I wrote two different ways:
First:
def exponents(bases, powers):
lst = []
for p in powers:
for b in bases:
lst.append(b ** p)
return lst
print(exponents([2, 3, 4], [1, 2, 3]))
This prints:
[2, 3, 4, 4, 9, 16, 8, 27, 64]
These values are wrong.
Second:
def exponents(bases, powers):
lst = []
for b in bases:
for p in powers:
lst.append(b ** p)
return lst
print(exponents([2, 3, 4], [1, 2, 3]))
This prints:
[2, 4, 8, 3, 9, 27, 4, 16, 64]
These are the correct values.
Why do these two very similar functions give different values? Is it related to floating point error?
Both functions are correct. You changed the order in which you compute the results.
Rearrange the output to a tabular format:
[2, 3, 4,
4, 9, 16,
8, 27, 64]
vs
[2, 4, 8,
3, 9, 27,
4, 16, 64]
These are the same values, but with rows and columns switched ... just as you specified in your code when you switch the computation order.
Your first example expands to:
2**1
3**1
4**1
2**2
3**2
4**2
2**3
3**3
4**3
Because for each p, loop through b
That computes to [2, 3, 4, 4, 9, 16, 8, 27, 64]
Your second example expands to:
2**1
2**2
2**3
3**1
3**2
3**3
4**1
4**2
4**3
Because you want for each b, loop through p
This computes to [2, 4, 8, 3, 9, 27, 4, 16, 64]
The values are correct--the order is different based on the order of looping that you desire
The problem is I'm trying to compare nested list and list without the same value or element ?
lst3 = [1, 6, 7, 10, 13, 28]
lst4 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
lst5 = [list(filter(lambda x: x not in lst3, sublist)) for sublist in lst4]
which returns:
[[17, 18, 21, 32], [11, 14], [5, 8, 15, 16]]
but I would like to get the number that don't match from l3. Here an example:
[[1,6,7,10,28],[1,6,10],[1,7,13,28]]
I would like the results to be:
[[1,6,7,10,28],[1,6,10],[1,7,13,28]]
In your example you are comparing each element in each sublist with lst3.
lst5 = [list(filter(lambda x: x not in lst3, sublist)) for sublist in lst4]
Problem is that you are asking whether each x from sublist is not in lst3 which is going to give you the remaining results from the sublist. You may want to do it the other way around.
lst5 = [list(filter(lambda x: x not in sublist, lst3)) for sublist in lst4]
Not only does it give you the answers you want but I even noticed you made a mistake in your expected results:
[[1, 6, 7, 10, 28], [1, 6, 10], [7, 10, 13, 28]]
Compared to yours:
[[1, 6, 7, 10, 28], [1, 6, 10], [1, 7, 13, 28]]
(See the last nested array)
Online example:
https://onlinegdb.com/Hy8K8GPSB
Rather than using things like filter and lambda, you could more readably just use a list comprehension:
lst5 = [[x for x in lst3 if not x in sublist] for sublist in lst4]
Which is
[[1, 6, 7, 10, 28], [1, 6, 10], [7, 10, 13, 28]]
This differs slightly from what you gave as your expected output, but I think that you made a typographical error in the third sublist of that expected output.
I would take John Coleman's answer but tweak the word order for readability.
lst5 = [[x for x in lst3 if x not in sublist] for sublist in lst4]
I have two list that are two dimensional list with at least 100 rows. I would like to match c1 to c2 or vice versa. But the real problem is instead of typing in row by row from c1 to match c2. Is there a faster way to loop through all the rows from c1 to match all the rows from c2 ?
I tried c1[0] and c1[1] and c1[2]. This method will work but i would have to do alot of typing row by row. This will be to much typing especially if its alot of rows?
Here i have two list that are two dimensional list.
c1 = [[2, 6, 7],[2,4,6],[3,6,8]].....
c2 = [[13, 17, 18], [7, 11, 13], [5, 6, 8]].......
[list(filter(lambda x: x in c3, sublist)) for sublist in c2].
Say I have a list of lists:
list = [[2, 4, 3, 8],
[5, 6, 4, 3],
[1, 9, 5, 7],
[8, 3, 1, 2]]
What I'm trying to do is get the product of each row and column without duplication.
So I would get the product of row 1 and row 2 (2*5, 4*6, 3*4, 8*3), then the product of row 1 and row 3 (2*1, 4*9, 3*5, 8*7), then product of row 1 and row 4 (2*8, 4*3, 3*1, 8*2).
After row 1 is complete, move on to row 2 and get the product of row 2 and row 3 (5*1, 6*9, 4*5, 3*7), then the product of row 2 and 4 (5*8, 6*3, 4*1, 3*2).
Lastly, we do row 3 and row 4 (1*8, 9*3, 5*1, 7*2)
I'm trying to figure out how to do this with loops, but I can't seem to figure it out.
You can use numpy and itertools.combinations:
import numpy as np
from itertools import combinations
>>> [np.array(i)*j for i,j in combinations(li,2)]
[array([10, 24, 12, 24]), array([ 2, 36, 15, 56]), array([16, 12, 3, 16]), array([ 5, 54, 20, 21]), array([40, 18, 4, 6]), array([ 8, 27, 5, 14])]
>>>
>>> zip(*(tuple(x * y for x, y in itertools.combinations(row, 2)) for row in zip(*LL)))
[(10, 24, 12, 24), (2, 36, 15, 56), (16, 12, 3, 16), (5, 54, 20, 21), (40, 18, 4, 6), (8, 27, 5, 14)]
You could try something like this (Python 2.7, replace xrange by range if you are using Python 3)
list = [[2, 4, 3, 8],
[5, 6, 4, 3],
[1, 9, 5, 7],
[8, 3, 1, 2]]
def multiply_rows(a, b):
# Assuming all rows are the same length.
return [a[i] * b[i] for i in xrange(0, len(a))]
for i in xrange(0, len(list)): # Iterate through all the rows
for j in xrange(i+1, len(list)): # Making sure not to multiply the same rows twice
print(multiply_rows(list[i], list[j]))
An explicit solution without importing any module is
[[x*y for x, y in zip(rowx, rowy)]
for ix, rowx in enumerate(L)
for rowy in L[ix+1:]]
but of course it has three "loops", one for the product of two rows and two nested ones for getting all possible pairings of distinct rows.
They're list comprehension loops, but still loops.
PS: never call a list list in Python code. That would hide the name of a system type and (badly) surprise programmers.
Try this:
Even other solutions are great, but if you are a beginner this will be a great help.
from itertools import izip #faster than zip
from operator import mul
my_list=[[2, 4, 3, 8],
[5, 6, 4, 3],
[1, 9, 5, 7],
[8, 3, 1, 2]]
final_list=[]
for n,i in izip(*my_list):
final_list.append(reduce(mul,i,1))
print final_list
I used a big list to represent a lot of needed values, which is really complicated to me.
For example:
[[[a,b,c],[d,e,f]],
[[g,h,i],[j,k,l]],
[[o,p,u],[r,s,t]]]
And I want to combine the three major indices and their corresponding value together. I don't mean to concatenate.
For example the result would be:
[[(a+g+o),(b+h+p),(c+i+u)],[(d+j+r),(e+k+s),(f+l+t)]]
Can someone help me how to accomplish this result? Thanks!
Here you go. Since you said adding, I am assuming a, b, c, etc are all integers.
>> a = [[[1,2,3],[4,5,6]],
... [[7,8, 9],[10, 11, 12]],
... [[16, 17, 18],[13, 14, 15]]]
>>> temp_list = list(zip(*b) for b in zip(*a))
>>> result = [[sum(list(a)) for a in b] for b in temp_list]
>>> result
[[24, 27, 30], [27, 30, 33]]
An intimidating one-liner would be:
[[sum(list(a)) for a in b] for b in list(zip(*b) for b in zip(*a))]
Let's step through the code line by line.
zip(*a) will give you:
>>> zip(*a)
[([1, 2, 3], [7, 8, 9], [16, 17, 18]), ([4, 5, 6], [10, 11, 12], [13, 14, 15])]
It combined the first inner most lists of the sublists.
We need to do another zip on this.
list(zip(*b) for b in zip(*a)) will give us:
[[(1, 7, 16), (2, 8, 17), (3, 9, 18)], [(4, 10, 13), (5, 11, 14), (6, 12, 15)]]
Now we just need to sum these and create a list of lists. So we do:
[[sum(list(a)) for a in b] for b in temp_list]
If the lists are going to be large, I would suggest using itertools' version of zip called izip(). But izip() returns a generator and not a list. So, you would need to convert it to lists.
This kind of thing really calls for numpy:
>>> a = [[[ 1, 2, 3], [ 4, 5, 6]],
[ [ 7, 8, 9], [10,11,12]],
[ [13,14,15], [16,17,18]]]
>>> import numpy
>>> numpy.array(a).sum(axis=0)
array([[21, 24, 27],
[30, 33, 36]])
The array function converts the data to a numpy array. Such arrays can be manipulated quite powerfully. In your case, you want to sum along the first (that is, zeroth) axis. This is done by invoking sum(axis=0).