Possible Combination of Lists inside a Single List - python

Given List
[[1,2],[3,4],[5,6]]
I want output as 3 different list as follows
[1,2,3,4],[3,4,5,6],[1,2,5,6]

You can use itertools.combinations to get all possible pairs
a = [[1, 2], [3, 4], [5, 6]]
>>> list(itertools.combinations(a, 2))
[([1, 2], [3, 4]), ([1, 2], [5, 6]), ([3, 4], [5, 6])]
To flatten the individual elements just map over them and add the two lists
>>> list(map(lambda x: x[0] + x[1], itertools.combinations(a, 2)))
[[1, 2, 3, 4], [1, 2, 5, 6], [3, 4, 5, 6]]

Simply Use Enumerate Function,
>>> x=[[1,2],[3,4],[5,6]]
>>> z = [x[index-len(x)] + x[index+1 - len(x)] for index, rec in enumerate(x)]
>>> z
>>> [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 1, 2]]

Related

Removing elements from sublists in Python

I have two lists A1 and J1 containing many sublists. From each sublist of A1[0], I want to remove the element specified in J1[0]. I present the current and expected outputs.
A1 = [[[1, 3, 4, 6], [0, 2, 3, 5]], [[1, 3, 4, 6], [1, 3, 4, 6]]]
J1 = [[[1], [2]], [[1], [4]]]
arD = []
for i in range(0,len(A1)):
for j in range(0,len(J1)):
C=set(A1[i][j])-set(J1[i][j])
D=list(C)
arD.append(D)
D=list(arD)
print("D =",D)
The current output is
D = [[3, 4, 6], [0, 3, 5], [3, 4, 6], [1, 3, 6]]
The expected output is
D = [[[3, 4, 6], [0, 3, 5]],[[3, 4, 6],[1, 3, 6]]]
Code:-
A1 = [[[1, 3, 4, 6], [0, 2, 3, 5]], [[1, 3, 4, 6], [1, 3, 4, 6]]]
J1 = [[[1], [2]], [[1], [4]]]
arD=[]
for i in range(0,len(A1)):
tmp=[] #Created a tmp variable list
for j in range(0,len(J1)):
C=set(A1[i][j])-set(J1[i][j])
tmp.append(list(C)) #Appending result in tmp variable
arD.append(tmp) #Storing tmp list as a list of lists in arD.
print("D =",arD)
Output:-
D = [[[3, 4, 6], [0, 3, 5]], [[3, 4, 6], [1, 3, 6]]]
Use list comprehension:
print([[[num for num in subsub_A1 if num not in subsub_J1]
for subsub_A1, subsub_J1 in zip(sub_A1, sub_J1)]
for sub_A1, sub_J1 in zip(A1, J1)])
Output:
[[[3, 4, 6], [0, 3, 5]], [[3, 4, 6], [1, 3, 6]]]
If you have an arbitrary list depth, consider using a recursive function:
def cleanup(A, J):
for l1, l2 in zip(A, J):
if l1 and isinstance(l1[0], list):
cleanup(l1, l2)
else:
s = set(l2)
l1[:] = [x for x in l1 if x not in s]
cleanup(A1, J1) # operation is in place
print(A1)
Output: [[[3, 4, 6], [0, 3, 5]], [[3, 4, 6], [1, 3, 6]]]
Try using remove method if you don't mind corrupting the original data:
from contextlib import suppress
A1 = [[[1, 3, 4, 6], [0, 2, 3, 5]], [[1, 3, 4, 6], [1, 3, 4, 6]]]
J1 = [[[1], [2]], [[1], [4]]]
for A, J in zip(A1, J1):
for a, j in zip(A, J):
for x in j:
with suppress(ValueError):
a.remove(x)
print(f"RESULT: {A1}")
output: RESULT: [[[3, 4, 6], [0, 3, 5]], [[3, 4, 6], [1, 3, 6]]]
Using list comprehension
[[list(set(A1[i][j])-set(J1[i][j])) for j in range(0,len(J1))] for i in range(0,len(A1))]
#output
[[[3, 4, 6], [0, 3, 5]], [[3, 4, 6], [1, 3, 6]]]

List item arrangement in python

I am looking for an efficient way to transform a given list into another list with degree n
here is input:
lst = [1, 2, 3, 4, 5, 6, 7]
n = 3
And favorable output is this:
[[1], [1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7], [7]]
It is basically like every element in resulting list is made of n consecutive elements from the given list except elements at starting and ending n-1 indices: 1, 2, 6, 7 in this example
Also for integer n, 1 <= n <= len(lst) is essential
You can use a comprehension with appropriate slices:
def chunks(lst, n=3):
return [lst[max(i,0):i+n] for i in range(1-n, len(lst))]
chunks([1, 2, 3, 4, 5, 6, 7])
# [[1], [1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7], [7]]
chunks([1, 2, 3, 4, 5], 4)
# [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5], [4, 5], [5]]
chunks([1, 2], 2)
# [[1], [1, 2], [2]]
chunks([1, 2, 3], 1)
# [[1], [2], [3]]
A more elegant version of this sliding window uses a collections.deque (as pointed out by #chepner in the comments):
from collections import deque
def chunks(lst, n=3):
window = deque(maxlen=n)
for x in lst:
window.append(x)
yield list(window)
while len(window) > 1:
window.popleft()
yield list(window)

Rank elements in nested list without sorting list

Let's say I have a nested list:
list = [[10, 2, 8, 4], [12, 6, 4, 1], [8, 4, 3, 2], [9, 3, 4, 6]]
I want to rank the elements in the sublist against each other to create a new nested list with the rankings.
result = [[1, 4, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4], [1, 4, 3, 2]]
in the first sublist 10 would be 1st, 8 2nd, etc.
There are already some good solutions. Here just another one - functional approach for reference:
No 3rd library used.
lst = # your lists - don't use builtin "list"
def ranking(nums):
ranks = {x:i for i, x in enumerate(sorted(nums, reverse=True),1)}
return [ranks[x] for x in nums] # quick mapping back: O(1)
Calling it:
result = list(map(ranking, lst))
As already mentioned in the comment, you can use numpy.argsort, using it twice gives you the rank for the values, which need to be subtracted from len of the sub list to rank from highest to lowest, you can use List-Comprehension to do it for all the sub lists.
>>> import numpy as np
>>> lst = [[10, 2, 8, 4], [12, 6, 4, 1], [8, 4, 3, 2], [9, 3, 4, 6]]
>>> [(len(sub)-np.argsort(sub).argsort()).tolist() for sub in lst]
[[1, 4, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4], [1, 4, 3, 2]]
You can even use 2D numpy array and negate the values, then directly call argsort twice on the resulting array, and finally add 1:
>>> (-np.array(lst)).argsort().argsort()+1
array([[1, 4, 2, 3],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 4, 3, 2]], dtype=int64)
You can use scipy.stats.rankdata:
my_list = [[10, 2, 8, 4], [12, 6, 4, 1], [8, 4, 3, 2], [9, 3, 4, 6]]
from scipy.stats import rankdata
[list(len(l)+1-rankdata(l).astype(int)) for l in my_list]
output:
[[1, 4, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4], [1, 4, 3, 2]]
Without numpy/scipy:
[[sorted(li, reverse=True).index(x)+1 for x in li] for li in data]
[[1, 4, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4], [1, 4, 3, 2]]
Another solution with no external libraries, and with a better time complexity, just in case your sublists are a bit longer than 4 items (this has some overhead but I presume it is O(n log n) because of the call to sorted).
def rank_all(ls):
result = []
for subls in ls:
pairs = sorted([(subls[j],j) for j in range(len(subls))], reverse=True)
ranked = [0] * len(subls)
for j,p in enumerate(pairs):
ranked[p[1]]=j+1
result.append(ranked)
return result

How to replace indexes by values from different list?

I have two lists:
test_list1 = [2, 3, 4, 5, 2, 4]
test_list2 = [[1, 5], [4, 2, 3], [0]]
I want to replace the indexes in test_list2 by the values in test_list1 such that the result would be:
[[3, 4], [2, 4, 5], [2]]
I have tried this:
res = [test_list1[idx] for idx in test_list2]
I have notice that my code only works for a list without sublists
A oneliner with list comprehension and map function could look like this:
test_list1 = [2, 3, 4, 5, 2, 4]
test_list2 = [[1, 5], [4, 2, 3], [0]]
output = list(map(lambda x: [test_list1[y] for y in x], test_list2))
print(output)
# [[3, 4], [2, 4, 5], [2]]
You can use a recursive function. This will go through an arbitarily nested list, replacing the values.
def replace(lst, replacements):
for i, val in enumerate(lst):
if isinstance(val, list):
replace(val, replacements)
else:
lst[i] = replacements[val]
test_list1 = [2, 3, 4, 5, 2, 4]
test_list2 = [[1, 5], [4, 2, 3], [0]]
replace(test_list2, test_list1)
print(test_list2)
Gives:
[[3, 4], [2, 4, 5], [2]]

I am trying to make a big list by using a present list but it's not working, can anybody explain why is this happening?

list1=[0,1,2]
mega_list=[]
for x in range(4):
print(list1)
mega_list.append(list1)
list1.pop(0)
list1.insert(2,list1[1]+1)
print(mega_list)
This is because you are adding a reference to list1 to mega_list. That is to say, at the end of the for loop you really have this:
mega_list = [list1, list1, list1, list1]
But, after the loop, list1 = [4, 5, 6], so that's why you get the output:
[[4, 5, 6], [4, 5, 6], [4, 5, 6], [4, 5, 6]]
To fix this, make a copy of the list before iterating further:
list1=[0,1,2]
mega_list=[]
for x in range(4):
print(list1)
mega_list.append(list1.copy())
list1.pop(0)
list1.insert(2, list1[1]+1)
print(mega_list)
Which outputs:
[0, 1, 2]
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]
list1=[0,1,2]
mega_list=[]
for x in range(4):
# Adds list1 as an element
mega_list.append(list1)
# Increments each element of list1
list1 = [x+1 for x in list1]
print(mega_list)
>>>[[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]
You need to create a copy of the list, rather use the same instance in each append, e.g.:
list1=[0,1,2]
mega_list=[]
for x in range(5):
mega_list.append(list1[:])
list1.pop(0)
list1.insert(2,list1[1]+1)
print(mega_list) # [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
An alternative, is just use indexes into a full list of the input values, e.g.:
list1=list(range(7)) # [0,1,2,3,4,5,6]
mega_list=[]
for i in range(len(list1)-3+1):
mega_list.append(list1[i:i+3])
print(mega_list) # [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
One alternative is to create a generalized nwise() function using itertools:
import itertools as it
def nwise(iterable, n):
ts = it.tee(list1, n)
for c, t in enumerate(ts):
next(it.islice(t, c, c), None)
return zip(*ts)
list1 = list(range(7))
mega_list = [x for x in nwise(list1, 3)]
print(mega_list) # [(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6)]

Categories