Python: Sorting a List - python

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]

Related

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

Avoid duplicates in nested loop 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)

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]

Maximizing space in a list

So I want to see if there is a possible way for me to maximize space in a list. For example:
lists = [3, 3, 3, 3, 3]
Maximum Value = 4 #from user input
Output = [3, 0, 4, 4, 4]
Process in each step:
Start: [3, 3, 3, 3, 3] #start
[3, 3, 3, 2, 4] #takes 1 number from lists[3] and puts it in lists[4] so that that is equal to 4
[3, 3, 1, 4, 4] #takes 2 numbers from(since 4 - lists[3] = 2 lists[2] and puts it in lists[3]
Finish:[3, 0, 1, 4, 4] #puts 3 numbers from lists[1] and puts them in lists[2](4 - lists[2] = 3) and now that there is a zero it should stop the program
Basically, the code should start at the back and fill in space in each value going down the list until one of the values is equal to 4 or 0 or until it reaches the start of the list.
1 last thing:
This should work with any list length and even if there are 0's after the last number. For example:
list = [3, 3, 5, 2, 7, 2, 3, 0, 0, 0, 0, 4]
MaximumValue = 4
Step 1: [3, 3, 5, 2, 7, 2, 3, 0, 0, 0, 0, 4]
[3, 3, 5, 2, 7, 1, 4, 0, 0, 0, 0, 4]
[3, 3, 5, 2, 4, 4, 4, 0, 0, 0, 0, 4]
[3, 3, 3, 4, 4, 4, 4, 0, 0, 0, 0, 4]
[3, 2, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4]
Finish: [1, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4] #reached lists[0] so stop program
You don't need all those intermediate steps. You can produce the list directly with easy division and remainder calculations.
>>> l = [3, 3, 5, 2, 7, 2, 3, 0, 0, 0, 0, 4]
>>> m = 4
>>> [m] * (sum(l) / m) + [sum(l) % m] + [0] * (len(l) - sum(l) / m - 1)
[4, 4, 4, 4, 4, 4, 4, 1, 0, 0, 0, 0]
>>>
This is sample code, maybe has better way.
lis = [3, 3, 5, 2, 7, 2, 3, 0, 0, 0, 0, 4]
MaximumValue = 4
start_index = 0
for i,v in enumerate(lis):
start_index = i
if v == 0:
start_index = i - 1
break
for i in range(start_index, 0, -1):
diff = MaximumValue - lis[i]
if diff >= 0:
lis[i] += diff
lis[i-1] -= diff
if lis[i-1] == 0:
break
print(lis)
Output:
[1, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 4]

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