List item arrangement in python - 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)

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]]]

How to join lists inside two or more different lists in arranged order?

I have three lists as follows.
A = [1, 2, 3]; B = [[3, 4, 5], [4, 5, 6], [4, 5, 7], [7, 4, 3]]; C = [[2, 3, 1], [2, 3, 3], [2, 4, 5], [4, 5, 6], [7, 3, 1]]
I want to create another list containing all the above inner lists starting from A to C.
Desired = [elements of A, elements of B, elements of C] just like this.
Desired = [[1, 2, 3], [3, 4, 5], [4, 5, 6], [4, 5, 7], [7, 4, 3], [2, 3, 1], [2, 3, 3], [2, 4, 5], [4, 5, 6], [7, 3, 1]]
It seems like you know which list is nested (B and C) and which isn't (A). If that's the case then you could simply do:
result = [A] + B + C
If you don't know but can determine the nestedness by looking at the first item, then you could do:
result = [
item
for numbers in (A, B, C)
for item in (numbers if isinstance(numbers[0], list) else [numbers])
]
If that's also not the case, i.e. there could be mixed lists (lists that contain numbers and lists), then you could use itertools.groupby from the standard library:
from itertools import groupby
result = []
for key, group in groupby(A + B + C, key=lambda item: isinstance(item, list)):
if not key:
group = [[*group]]
result.extend(group)
Results for all versions (with A, B and C like provided):
[[1, 2, 3], [3, 4, 5], [4, 5, 6], [4, 5, 7], [7, 4, 3],
[2, 3, 1], [2, 3, 3], [2, 4, 5], [4, 5, 6], [7, 3, 1]]
The method I use below is to see if the inner_list contents are infact a list of themselves.
If they are, then append the inner list.
If they are not, then append the outer_list.
A = [1, 2, 3];
B = [[3, 4, 5], [4, 5, 6], [4, 5, 7], [7, 4, 3]];
C = [[2, 3, 1], [2, 3, 3], [2, 4, 5], [4, 5, 6], [7, 3, 1]]
desired = []
for outer_list in (A,B,C):
list_state = False
for inner_list in outer_list:
if isinstance(inner_list, list):
desired.append(inner_list)
else:
list_state = True
# Add outer_list only if the inner_list was not a list
if list_state:
desired.append(outer_list)
print(desired)
OUTPUT:
[[1, 2, 3], [3, 4, 5], [4, 5, 6], [4, 5, 7], [7, 4, 3], [2, 3, 1], [2, 3, 3], [2, 4, 5], [4, 5, 6], [7, 3, 1]]
I made something to make a list to an nested list if it is not.
A = [1, 2, 3]
B = [[3, 4, 5], [4, 5, 6], [4, 5, 7], [7, 4, 3]]
C = [[2, 3, 1], [2, 3, 3], [2, 4, 5], [4, 5, 6], [7, 3, 1]]
listt = [ 'A', 'B', 'C' ]
des = []
for i in listt:
if type((globals()[i])[0]) != list:
globals()[i] = [[i for i in globals()[i]]] #turns into nested list if not (line 7-9)
for i in (A,B,C):
for x in i:
des.append(x)
print(des)
Output:
[[1, 2, 3], [3, 4, 5], [4, 5, 6], [4, 5, 7], [7, 4, 3], [2, 3, 1], [2, 3, 3], [2, 4, 5], [4, 5, 6], [7, 3, 1]]

How to get data from nested lists recursively?

I have a nested array of arbitrary length and trying to retrieve data from it in the following order: items in the [0] element of the array form somewhat like a tree and as a result I should return all possible combinations with them.
For example:
some_list = [[1, 2], [3, 4], [5, 6, 7]]
the result should be:
[1, 3, 5], [1, 3, 6], [1, 3, 7], [1, 4, 5], [1, 4, 6], [1, 4, 7],
[2, 3, 5], [2, 3, 6], [2, 3, 7], [2, 4, 5], [2, 4, 6], [2, 4, 7]
I tried loops but they do not seem a good decision.
I think it should be recursion, but don't know how to apply it.
this is an example of a recursive function that would calculate the cartesian product of all the input lists
def cp(x):
l = []
# loop over the lists in the list
# if there is only 1 list left in the input then return it
if len(x) > 1:
for i in x[0]: # loop over the first list in the input
for j in cp(x[1:]): # loop over the cartesian product of the remaining lists in the input
l.append([i]) # add a new sub-list starting with value of i
if isinstance(j,list): # extend it with the result of the cartesian product of the remaining lists
l[-1].extend(j)
else:
l[-1].append(j)
else:
l = x[0]
return l
print(cp([[1, 2], [3, 4], [5, 6, 7]]))
gives the output
[[1, 3, 5], [1, 3, 6], [1, 3, 7], [1, 4, 5], [1, 4, 6], [1, 4, 7], [2, 3, 5], [2, 3, 6], [2, 3, 7], [2, 4, 5], [2, 4, 6], [2, 4, 7]]
have a look here for implementations in different programming languages:
https://rosettacode.org/wiki/Cartesian_product_of_two_or_more_lists
You can do it with nested for loops, or for convenience, with itertools.product:
from itertools import product
some_list = [[1, 2], [3, 4], [5, 6, 7]]
prod = [list(i) for i in product(*some_list)]
print(prod)
Output:
[[1, 3, 5], [1, 3, 6], [1, 3, 7], [1, 4, 5], [1, 4, 6], [1, 4, 7], [2, 3, 5], [2, 3, 6], [2, 3, 7], [2, 4, 5], [2, 4, 6], [2, 4, 7]]

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 count the number of sublists based on common elements from a nested list in python?

I have a list of lists like this: [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3], [3, 4]]. How can I count the lists which are sublists of more than two lists? For example, here [2, 3] and [3, 4] would be the lists that are sublists of first 3 lists. I want to get rid of them.
This comprehension should do it:
data = [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3], [3, 4]]
solution = [i for i in data if sum([1 for j in data if set(i).issubset(set(j))]) < 3]
set_list = [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3], [3, 4]]
check_list = [[2, 3], [3, 4]]
sublist_to_list = {}
for set in set_list:
for i, sublist in enumerate(check_list):
count = 0
for element in sublist:
if element in set:
count += 1
if count == len(sublist):
if i not in sublist_to_list:
sublist_to_list[i] = [set]
else:
sublist_to_list[i].append(set)
print(sublist_to_list)
Output: {0: [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3]], 1: [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [3, 4]]}
which means [2, 3] is subset of [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3]]
and [3, 4] is subset of [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [3, 4]]
You can first make a function that gets sub lists of a list:
def sublists(lst):
length = len(lst)
for size in range(1, length + 1):
for start in range(length - size + 1):
yield lst[start:start+size]
Which works as follows:
>>> list(sublists([1, 2, 3, 4, 5]))
[[1], [2], [3], [4], [5], [1, 2], [2, 3], [3, 4], [4, 5], [1, 2, 3], [2, 3, 4], [3, 4, 5], [1, 2, 3, 4], [2, 3, 4, 5], [1, 2, 3, 4, 5]]
Then you can use this to collect all the sublists list indices into a collections.defaultdict:
from collections import defaultdict
lsts = [[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7], [2, 3], [3, 4]]
d = defaultdict(list)
for i, lst in enumerate(lsts):
subs = sublists(lst)
while True:
try:
curr = tuple(next(subs))
d[curr].append(i)
except StopIteration:
break
Which will have tuple keys for the sublists, and the list indices as the values.
Then to determine sub lists that occur more than twice in all the lists, you can check if the set of all the indices has a length of more than two:
print([list(k) for k, v in d.items() if len(set(v)) > 2])
Which will give the following sublists:
[[2], [3], [4], [5], [2, 3], [3, 4], [4, 5], [2, 3, 4], [3, 4, 5], [2, 3, 4, 5]]

Categories