Avoid duplicates in nested loop python - python

So i have nested loops and array
[[0, 1], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4]]:
for x in string_list:
for y in string_list:
print(x,y)
provides me the output
[0, 1] [0, 1]
[0, 1] [0, 1, 2, 3, 4, 5, 6]
[0, 1] [0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5, 6] [0, 1]
[0, 1, 2, 3, 4, 5, 6] [0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6] [0, 1, 2, 3, 4]
[0, 1, 2, 3, 4] [0, 1]
[0, 1, 2, 3, 4] [0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4] [0, 1, 2, 3, 4]
But i have a lot of duplicates pairs and i did:
for x in range(0, len(string_list)):
for y in range(x+1, len(string_list)):
print(x,y, string_list)
but it's working only for 2 digit pairs.
So what i want is:
[0, 1] [0, 1]
[0, 1] [0, 1, 2, 3, 4, 5, 6]
[0, 1] [0, 1, 2, 3, 4]
**[0, 1, 2, 3, 4, 5, 6] [0, 1]** // avoid to output that pair cause we had that one
[0, 1, 2, 3, 4, 5, 6] [0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6] [0, 1, 2, 3, 4]
[0, 1, 2, 3, 4] [0, 1]
**[0, 1, 2, 3, 4] [0, 1, 2, 3, 4, 5, 6]** // avoid to output that pair cause we had that one
[0, 1, 2, 3, 4] [0, 1, 2, 3, 4]
does it possible to do without using itertools ?
Thank you!

for k, x in enumerate(string_list):
for y in string_list[k:]:
print(x,y)

You can use itertools.combinations:
for x, y in it.combinations(string_list, 2):
# process x, y

Obviously using itertools.combinations is ideal, but since you said you don't want to use itertools, you could use a set comprehension to build the set of unique combinations (you have to convert the lists to tuples to make them hashable), then convert them back to lists as needed:
[list(list(t) for t in f) for f in {
frozenset((tuple(x), tuple(y))) for y in string_list for x in string_list
}]

You can put a continue statement in the inner loop to skip duplicates:
for x in string_list:
for y in string_list:
if x == y:
continue
print(x,y)

Related

delete elements from lists in a nested list [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 1 year ago.
I am using python, I have a nested list like this
sequences_list = [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]
I want to get a sort of sequences like this
sequences_list = [[0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4, 5]]
this is my code
k = 1
j = 0
while (k <= len(sequences_list)):
del sequences_list[j][k:]
k = k+1
j = j+1
print(sequences_list)
the result i get is
[[0], [0], [0], [0], [0], [0]]
Try this one
sequences_list = [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]
print([element[0:po+1] for po,element in enumerate(sequences_list)])

Append "i" element with "j" element with "k" element in python

I have 3 arrays that correspond to coordinates and data of a sparse matrix:
cx=[3, 4, 3, 0, 1, 2, 1, 2]
rx=[0, 0, 1, 2, 2, 2, 3, 4]
data=[0.73646372, 0.42238729, 0.20987735, 0.33721646, 0.66935198, 0.13533819, 0.64143482, 0.004114]
And I need this output:
[[3, 0 , 0.73646372],
[4, 0 , 0.42238729],
[3, 1 , 0.20987735],
....
I have tried .append() with no luck :(
Why not use zip method?
cx=[3, 4, 3, 0, 1, 2, 1, 2]
rx=[0, 0, 1, 2, 2, 2, 3, 4]
data=[0.73646372, 0.42238729, 0.20987735, 0.33721646, 0.66935198, 0.13533819, 0.64143482, 0.004114]
new_list=[]
for i in zip(cx, rx,data):
print(list(i))
However, if you want a traditional solution:
cx=[3, 4, 3, 0, 1, 2, 1, 2]
rx=[0, 0, 1, 2, 2, 2, 3, 4]
data=[0.73646372, 0.42238729, 0.20987735, 0.33721646, 0.66935198, 0.13533819, 0.64143482, 0.004114]
new_list=[]
for i,j in enumerate(cx):
new_list.append([cx[i],rx[i],data[i]])
print(new_list)
More compact solutions
k=[list(i) for i in zip(cx, rx,data)]
j=[[cx[i],rx[i],data[i]] for i,j in enumerate(cx)]
You can use zip()
new = [list(i) for i in zip(cx,rx,data)]
output
[[3, 0, 0.73646372], [4, 0, 0.42238729], [3, 1, 0.20987735], [0, 2, 0.33721646], [1, 2, 0.66935198], [2, 2, 0.13533819], [1, 3, 0.64143482], [2, 4, 0.004114]]

how to apply filter function to items in multiple list?

I wanna get values from multiple(?) list, which is not 0(I think filter can be one of solutions).
list as below:
>>ls = [[i for i in np.random.randint(0, 5, 5)] for _ in range(7)]
>>ls
>>
[[2, 3, 3, 0, 0],
[4, 2, 4, 3, 2],
[1, 2, 4, 2, 4],
[2, 3, 4, 3, 1],
[0, 1, 0, 3, 0],
[3, 4, 4, 4, 3],
[3, 4, 3, 3, 2]]
Expected result is:
[2,3,3,4,2,4,3,2,1,2,4,2,4,2,3,4,3,1,1,3,3,4,4,4,3,3,4,3,3,2]
I tried using filter function, wanted expand this idea, but I failed:
>> [elem for elem in filter(lambda x: x if x != 0 else False, ls[0])]
>>
[2, 3, 3]
I wanna find fastest way to get expected result, not using for loop.
Would you suggest any good idea?
Edit:
Oops, Sorry for confusing you.
I saying 'not usting for loop' means, I wanna use list comprehension instead of for loop, because I heard list comprehension fater than for loop.
Use a nested list comprehension:
[j for i in ls for j in i if j != 0]
ls = [[i for i in np.random.randint(0, 5, 5)] for _ in range(7)]
[[1, 0, 3, 0, 0],
[1, 2, 2, 3, 0],
[1, 1, 1, 4, 3],
[1, 0, 3, 0, 4],
[2, 0, 3, 0, 2],
[1, 0, 4, 4, 0],
[2, 4, 1, 1, 2]]
[j for i in ls for j in i if j != 0]
# [1, 3, 1, 2, 2, 3, 1, 1, 1, 4, 3, 1, 3, 4, 2, 3, 2, 1, 4, 4, 2, 4, 1, 1, 2]
If you want to avoid any explicit looping here's an option using itertools.chain and filter:
from itertools import chain
list(filter(lambda x: x != 0, chain(*ls)))
# [1, 3, 1, 2, 2, 3, 1, 1, 1, 4, 3, 1, 3, 4, 2, 3, 2, 1, 4, 4, 2, 4, 1, 1, 2]
Looks like you're also using NumPy for creating the list. Note that this would be way simpler and more efficient using np.nonzero:
import numpy as np
a = np.random.randint(0, 5, (7,5))
a[np.nonzero(a)]
# [1, 3, 1, 2, 2, 3, 1, 1, 1, 4, 3, 1, 3, 4, 2, 3, 2, 1, 4, 4, 2, 4, 1, 1, 2]
Adding to #yatu's answer, since it's 0, you can just do if x:
print([x for i in ls for x in i if x])
Or without loop:
print(np.array(ls).flatten()[np.array(ls).flatten() != 0].tolist())
Both output:
[1, 4, 4, 2, 1, 3, 3, 4, 4, 1, 3, 3, 2, 2, 2, 1, 4, 2, 2, 1, 4, 1, 2, 3, 2, 4]

Python: Sorting a List

I'm trying to sort a list by moving through it and checking if a given element of the list is greater than the next element of the list, and if so, moving it accordingly so that the smaller number is to the left, larger to the right.
This is the code I have so far:
L = [3, 4, 1, 5, 2, 0]
for i in range(0, (len(L)-1)):
if L[i] > L[i+1]:
L[i], L[i+1] = L[i+1], L[i]
print(L)
The output of this for the three iterations are as follows:
[3, 1, 4, 5, 2, 0]
[3, 1, 4, 2, 5, 0]
[3, 1, 4, 2, 0, 5]
My goal is to get it to read [0, 1, 2, 3, 4, 5]. I realize I can just use the sorted() function but I'd prefer not to. I was thinking that I could try and iterate the for loop over the list multiple times, but I am unsure as to how to do so.
Currently you only compare each element and it's successor. However you really want to compare it to all following elements (starting with i+1 and ending with len(L)), so you need a double loop:
L = [3, 4, 1, 5, 2, 0]
for i in range(0, (len(L)-1)):
for j in range(i+1, len(L)):
if L[i] > L[j]:
L[i], L[j] = L[j], L[i]
print(L)
Which prints the following steps:
[1, 4, 3, 5, 2, 0]
[0, 4, 3, 5, 2, 1]
[0, 3, 4, 5, 2, 1]
[0, 2, 4, 5, 3, 1]
[0, 1, 4, 5, 3, 2]
[0, 1, 3, 5, 4, 2]
[0, 1, 2, 5, 4, 3]
[0, 1, 2, 4, 5, 3]
[0, 1, 2, 3, 5, 4]
[0, 1, 2, 3, 4, 5]
You could just put it inside a while loop:
L = [3, 4, 1, 5, 2, 0]
flag = True
while flag:
flag = False
for i in range(0, (len(L)-1)):
if L[i] > L[i+1]:
L[i], L[i+1] = L[i+1], L[i]
flag = True
print(L)
Output:
[3, 1, 4, 5, 2, 0]
[3, 1, 4, 2, 5, 0]
[3, 1, 4, 2, 0, 5]
[1, 3, 4, 2, 0, 5]
[1, 3, 2, 4, 0, 5]
[1, 3, 2, 0, 4, 5]
[1, 2, 3, 0, 4, 5]
[1, 2, 0, 3, 4, 5]
[1, 0, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5]

Reversing equal sized chunks of a list

If I have a list:
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3]
My goal is to split it into equal sized chunks of n, reverse each chunk, and then put the chunks back in order. So, for the example above, for chunk size 4, I'd get:
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3]
[_________] [_________] [________] [______]
| | | |
1 2 3 4 (this is smaller than 4 but receives the same treatment)
||
[4, 3, 2, 1, 4, 3, 2, 1, 4, 3, 2, 1, 3, 2, 1]
This is what I have:
n = 4
l = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3]
chunks = [l[i : i + n] for i in range(0, len(l), n)]
print(chunks)
# [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3]]
for i in range(len(chunks)):
chunks[i] = list(reversed(chunks[i])) # or chunks[i] = chunks[i][::-1]
from functools import reduce
out = list(reduce(lambda x, y: x + y, chunks))
print(out)
# [4, 3, 2, 1, 4, 3, 2, 1, 4, 3, 2, 1, 3, 2, 1]
I don't think this is very good though. Is there another way that better utilises python's libraries than this?
What about using the following list comprehension:
[x for i in range(0,len(l),4) for x in reversed(l[i:i+4])]
or with parameterized chunk size:
chunk = 4
[x for i in range(0,len(l),chunk) for x in reversed(l[i:i+chunk])]
This generates:
>>> [x for i in range(0,len(l),4) for x in reversed(l[i:i+4])]
[4, 3, 2, 1, 4, 3, 2, 1, 4, 3, 2, 1, 3, 2, 1]
for your given list. Furthermore I guess it is quite declarative (the reversed(..) indicates that you reverse, etc.)
List comprehension sure looks nice, but perhaps it is more readable to simply do a for loop and update each chunk by itself:
lst = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3]
chunk = 4
for i in range(0, len(lst), chunk):
lst[i:i+chunk] = reversed(lst[i:i+chunk])
print(lst)
# [4, 3, 2, 1, 4, 3, 2, 1, 4, 3, 2, 1, 3, 2, 1]
If you do not want the update in place, you can do out = lst[:] at the start.

Categories