Python not iterating over array with for loop [duplicate] - python

This question already has answers here:
Python invert every two elements of list
(5 answers)
Closed 3 months ago.
Write a program that fills an array of 10 elements with random numbers from 1 to 10, and then swaps the first element with the second, the third with the fourth, and so on. Display the original and transformed array
Here is my solution, but Python doesn't want to sort the array and it stays the same:
from random import randint
numbers = []
for i in range(10):
numbers.append(randint(1, 10))
print(numbers)
a = 0
for a in range(10):
numbers[-1], numbers[i] = numbers[i], numbers[-1]
a = a + 2
print(numbers)
I have tried replacing elements with a loop by numbers[a] = numbers[a+1] , But I kept getting the error:
IndexError: list index out of range

There's a couple things here:
1: as #bereal said, range() has a tird optional step argument, and I've never seen a better time to use it. Check out the documentation for range() https://docs.python.org/3/library/functions.html#func-range
2: I see you reference numbers[-1] even though I think you mean number[-i], it will still reference numbers[-1] on the first iteration, thereby giving an error.

You can make the swap when its not an even number like this:
for a in range(10):
if a % 2 == 1:
tempNumber = numbers[a]
numbers[a] = numbers[a-1]
numbers[a-1] = tempNumber
And then you will have
First output:
[9, 7, 4, 7, 4, 3, 1, 9, 9, 9]
Final output:
[7, 9, 7, 4, 3, 4, 9, 1, 9, 9]

Related

iterating list through a function [duplicate]

This question already has answers here:
Accessing the index in 'for' loops
(26 answers)
Closed 8 months ago.
I have a function that takes a list as parameter (have used a very simple function here to focus on the point of my question).
def some_lst_func(lst):
foo = len(lst)
return foo
lst1= [1, 6, 6, 7, 7, 5]
print(some_lst_func(lst1))
For the whole list this works fine, but I want to incrementally pass the list ([1], [1,6].....) to the function and record each output (i.e. increasing length of list).
Below is what I have tried but is clearly not correct, and not sure what the output is that I am getting, what I would expect is
1
2
3...
for num in lst1:
print(some_lst_func(lst1[:num]))
You need to loop over indices, not items:
def some_lst_func(lst):
return len(lst)
lst1= [1, 6, 6, 7, 7, 5]
for num in range(1, len(lst1) + 1):
print(some_lst_func(lst1[:num]))
# 1
# 2
# 3
# 4
# 5
# 6
# alternatively, using enumerate:
for num, _ in enumerate(lst1, start=1):
print(some_lst_func(lst1[:num]))

Group Consecutive Increasing Numbers in List [duplicate]

This question already has answers here:
Decompose a list of integers into lists of increasing sequences
(6 answers)
Closed 2 years ago.
How can I group together consecutive increasing integers in a list? For example, I have the following list of integers:
numbers = [0, 5, 8, 3, 4, 6, 1]
I would like to group elements together as follow:
[[0, 5, 8], [3, 4, 6], [1]]
While the next integer is more than previous, keep adding to the same nested list; ones the next integer is smaller, add nested list to main list and start again.
I have tried few different ways (while loop, for loop, enumerate and range), but cannot figure out how to make it append to the same nested list as long as next integer is larger.
result = []
while (len(numbers) - 1) != 0:
group = []
first = numbers.pop(0)
second = numbers[0]
while first < second:
group.append(first)
if first > second:
result.append(group)
break
You could use a for loop:
numbers = [0, 5, 8, 3, 4, 6, 1]
result = [[]]
last_num = numbers[0] # last number (to check if the next number is greater or equal)
for number in numbers:
if number < last_num:
result.append([]) # add a new consecutive list
result[-1].append(number)
last_num = number # set last_num to this number, so it can be used later
print(result)
NOTE: This doesn't use .pop(), so the numbers list stays intact. Also, one loop = O(N) time complexity!!
If pandas are allowed, I would do this:
import pandas as pd
numbers = [0, 5, 8, 3, 4, 6, 1]
df = pd.DataFrame({'n':numbers})
[ g['n'].values.tolist() for _,g in df.groupby((df['n'].diff()<0).cumsum())]
produces
[[0, 5, 8], [3, 4, 6], [1]]
You can do this:
numbers = [0, 5, 8, 3, 4, 6, 1]
result = []
while len(numbers) != 0:
secondresult = []
for _ in range(3):
if numbers != []:
toappend = numbers.pop(0)
secondresult.append(toappend)
else:
continue
result.append(secondresult)
print(result)
use while and for loops. and append them to secondresult and result

Strange behavior with python slicing [duplicate]

This question already has answers here:
Reversing a list slice in python
(3 answers)
Closed 3 years ago.
Suppose we have this list:
>>> a = [x for x in range(10)]
>>> print(a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Separately, both ways to slice work as expected:
>>> a[3:8]
[3, 4, 5, 6, 7]
>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
But, when combined:
>>> a[3:8:-1]
[]
I would expect it to be [7, 6, 5 ,4, 3] or perhaps [6, 5, 4, 3, 2] (if reversing happened first).
It is also interesting to consider what happens when either start or stop parameters are not passed:
>>> a[:5:-1]
[9, 8, 7, 6]
This is almost what I would expect, only its one item short. Tested this with numpy and it seems to behave in the same way.
Whats going on here?
With
a[3:8:-1]
The start and stop positions of the slice aren't adjusted based on the step. With a negative step, you're having it go backwards from 3, but there are no elements with indices in the range 3 to 8 counting back from 3, so you get an empty list.
You need to set the start and stop accordingly:
a[8:3:-1]
Which will count back from 8 to 4.
a[3:8:-1] instructs python to start from 3 and go to 8 by steps of -1
This creates an empty list: it's not possible to reach 8 from 3 by adding -1 (just like list(range(3,8,-1)) which gives an empty list too)
When you do a[:5:-1] then start is the default start, which python sets to "end of list" so it "works"
Same as when you do a[::-1] the start & stop are the default ones, and python understands that they're from end to start (else this notation wouldn't be useable)
This behavior is explained in the documentation.
The slice of s from i to j is defined as the sequence of items with index k such that i <= k < j. If i or j is greater than len(s), use len(s). If i is omitted or None, use 0. If j is omitted or None, use len(s). If i is greater than or equal to j, the slice is empty.
The slice of s from i to j with step k.... stopping when j is reached (but never including j). When k is positive, i and j are reduced to len(s) if they are greater. When k is negative, i and j are reduced to len(s) - 1 if they are greater. If i or j are omitted or None, they become “end” values (which end depends on the sign of k).

(Python) I need to remove the duplicate elements in a list (use remove funct; avoid typecasting). Trying to determine why my solution is incorrect

Specifications:
I want to use the remove function (in lists) and I'd prefer to avoid typecasting.
l = [2, 3, 3, 4, 6, 4, 6, 5]
q=len(l)
for i in range (0, q):
for g in range (i+1, q):
if l[g]==l[i]:
q-=1 #decremented q to account for reduction in list size.
l.remove(l[g])
print(l)
Error: if l[g]==l[i]:
IndexError: list index out of range
I know that similar questions have been asked by users previously. As the aforementioned constraints were absent in them, I would like to request you to treat this as a separate question. Thanks!
>>> l = [2, 3, 3, 4, 6, 4, 6, 5]
>>> s = set(l)
>>> t = sorted(s)
>>> print(t)
[2, 3, 4, 5, 6]
Using set is a simple and straight-forward way to filter your collection. If you don't need the list in a specific order, you can just use the set from thereon. The sorted function returns a list (using the default ordering).
Since you mentioned you don't want typecasting, so my solution is using while loop
l = [2, 3, 3, 4, 6, 4, 6, 5]
q=len(l)
i = 0
while i<len(l):
g = i+1
while (g < q):
if l[g]==l[i]:
q-=1 #decremented q to account for reduction in list size.
l.remove(l[g])
g += 1
i += 1
print(l)
Now, allow me to explain what was the problem in your code. When you use range function, it holds the starting and the ending value at the first run of the loop, so even if you change the limits afterwards in the loop, still, it won't change the range loop so eventually, you get index out of bounds error.
Hope this helps you :)
Your solution does not work, because range() store the value of q, and will ignore the change of q's value later. Eg:
>>> m = 10
>>> for i in range(m):
... m=0
... print(i)
...
0
1
2
3
4
5
6
7
8
9
Even if I change m, range() will still go 10 times in the loop. So, when you change the size of the list, even if you change q, you will still try to reach elements that does not exist anymore.

What is wrong with my sorting algorithm?

I am a beginner programmer and I've been trying to create my own sorting algorithm in Python, I don't understand why it outputs only some of the numbers that were present in the input. I put debug prints everywhere to understand the problem but still got nothing. The code should find and move to the final array the biggest number of the input array, and do that until the input array it's empty, but it seems to stop at some point. There was a person with a similar problem but the solution did not apply to me as well. This is the code:
array = [3, 6, 25, 4, 5, 24, 7, 15, 5, 2, 0, 8, 1] #just random numbers
output = []
while(len(array) > 0):
maximum = 0
for x in array:
maximum = max(maximum, x)
output.append(maximum)
tempArray = []
for x in array:
temp = array.pop()
if(temp < maximum):
tempArray.append(temp)
array = tempArray
print(output)
The problem is here:
for x in array:
temp = array.pop()
You're modifying the same list that you're iterating over. That's going to cause trouble.
Consider what happens when 5 is the maximum (and there are two 5s in the input.) One 5 gets added to output, the rest of the 5s are never added to tempArray.
To diagnose, put some debug prints in the loop, such as print(output, array) at the end of the outer loop. And maybe more in the inner loop. After seeing the problem (removing two things from array each inner iteration, this works.
array = [3, 6, 25, 4, 5, 24, 7, 15, 5, 2, 0, 8, 1] #just random numbers
output = []
while(array):
maximum = 0
for x in array:
maximum = max(maximum, x)
output.append(maximum)
tempArray = []
for x in array:
if(x < maximum):
tempArray.append(x)
array = tempArray
print(output)
There are, of course, easier and better ways to delete the max from array, and only delete one copy of max instead of all.

Categories