Iterating through a list and comparing places - Python - python

So, I am trying something simple. I am trying to go through a list, which, once sorted, I can see if the next number along is higher than the previous.
If this is so, I can add it into a new list:
def longestRun(L):
'''
assume L is not empty
'''
new_list=[]
list_place=0
# we then need to iterate along the sorted List L
print L[list_place]
print L[list_place+1]
if L[list_place] < L[list_place+1]
new_list+=L[list_place]
list_place+=1

L = [1, 2, 3]
list_place = 0
new_list = []
while list_place < len(L)-1:
print L[list_place]
if L[list_place] < L[list_place+1]:
new_list.append(L[list_place])
list_place+=1
print len(new_list)
To iterate, first you need a loop statement, like while. Second, if you don't increment list_place every time you iterate, once if statement evaluates to false, it goes into loop forever.

Related

how to loop through each element in list and increment by one

Hello i want to ask how to loop through each element and increment every time by one this is what i want first i want to sum 0 , 1, 3 ,6 , 10 and after that sum can somebody help me about that i don't know how to tell if it is loop through each element or iterate.It should look like these examples.I am sorry!
ls = [0, 1, 3, 6, 10]
ls = [1, 3, 6, 10]
ls = [3, 6, 10]
ls = [6, 10]
ls = [10]
ls = []
Here's the problem who i want to solve it :
https://www.codewars.com/kata/5ce399e0047a45001c853c2b/train/python
I tried this but it doesn't work
def parts_sums(ls):
length_list = len(ls)
for i in range(0,length_list+1):
return length_list
Note that there is a built-in function sum() in Python that does that job probably better than any code you can write in Python.
sum([0, 1, 3, 6, 10])
However, if you want to practice writing your sum function by iterating through a list and summing all the elements, this is how you do it.
def my_sum(ls):
result = 0
for i in range(len(ls)):
result += ls[i]
return result
First of all, you need to initialize a variable to hold your result. The range() function generates all values from 0 to x. The for-loop assigns all values generated by the range function to i in order and executes the indented block below. The += assignment increments the left-hand side variable by the right-hand side expression value. At last, we return the result.
And if you prefer using a while-loop,
def my_sum(ls):
result = 0
i = 0
while i < len(ls):
result += ls[i]
i += 1
return result
It's always good to consult Python documentation when you are not sure how to use its built-in function.
If you want the accumulated sum of all items reversed, you can take a look at the accumulate function in itertools.
from itertools import accumulate
def parts_sums(ls):
return list(accumulate(ls[::-1]))[::-1] + [0]
Or if you want to implement with a loop,
def parts_sums(ls):
result = []
part_sum = 0
for item in ls[::-1]:
result.append(part_sum)
part_sum += item
result.append(part_sum)
return result[::-1]
Or if you want to do it without reversing the list (say if you want to yield the results)
def parts_sums(ls):
result = []
part_sum = sum(ls)
for item in ls:
result.append(part_sum)
part_sum -= item
result.append(part_sum)
return result
Note the algorithm is still O(n), not that time complexity matters in this case.
For the question you have mentioned in codewars, you need to loop it thro 2 loops and keep reducing the first element in the inner loop for sum.
def parts_sums(ls):
# your code
sum = []
for i in range(len(ls)):
sum_temp =0
for j in range(i,len(ls)):
sum_temp += ls[j]
sum.append(sum_temp)
sum.append(0) # for the final empty list
return sum
print(parts_sums([0, 1, 3, 6, 10]))
This test will check the execution time too. So you need to be fast.
Naive approach
You can use sum or create your own sum.
def parts_sums(ls):
return [
sum(ls[i:])
for i in range(len(ls) + 1)
]
But i means you'll need to loop in a list twice. So it will be slow.
Sneaky approach
In a list like [a, b, c, d, e] you are calculating:
[a+b+c+d+e, a+b+c+d, a+b+c, a+b, a, 0]. So let's start from last to first element. [0, a, a+b, a+b+c, a+b+c+d, a+b+c+d+e]. Now we see a cumulative iteration:
So get loop in the list, get the element, sum it with last element of the result ([0]) list and add it as the last element to the result list. Lastly reverse the result.
def parts_sums(ls):
res = [0]
for i in range(len(ls)-1, -1, -1):
res.append(res[-1] + ls[i])
return res[::-1]

Why is variable behaving differently outside loop?

if i run this code:
def numbers_in_lists(string):
next_number = 0
count = 0
final_list = []
while count < len(string):
number = int(string[count])
if number > next_number:
final_list.append(number)
new = []
next_number = number
else:
new.append(number)
if new not in final_list:
final_list.append(new)
count += 1
print final_list
#testcases
string = '543987'
result = [5,[4,3],9,[8,7]]
print repr(string), numbers_in_lists(string) == result
i get this answer:
'543987' [5, [4, 3], 9, [8, 7]]
False
but if i put the number variable outside of the while loop like this:
def numbers_in_lists(string):
next_number = 0
count = 0
final_list = []
number = int(string[count])
while count < len(string):
if number > next_number:
final_list.append(number)
new = []
next_number = number
else:
new.append(number)
if new not in final_list:
final_list.append(new)
count += 1
print final_list
i get this answer:
'543987' [5, [5, 5, 5, 5, 5]]
False
I am a beginner and i have looked everywhere for the explanation as to why the number variable behaves differently outside of the loop? Also, why are the other variables ok outside of the loop but not number variable?
Any help would be much appreciated. Thankyou. :)
You declare number as
number = int(string[count])
So when
count = 0
This means that number will be the first character of your string (position [0]) converted to int. If you do not update number within your loop, it will never change. In your first version of the code, number is in your while loop.
while count < len(string):
number = int(string[count])
# more code
count += 1
Note at the end of the loop, you increment count. This means at the beginning of the next iteration, count now is incremented, so number will take on the value of the next character in your string.
A common misconception for beginners is that a variable is somehow "bound" to another variable. For example:
>>> a = 5
>>> b = a
>>> b
5
>>> a = 7
>>> b
5
See, even though a changed values from 5 to 7, b doesn't change because it is not "bound" to that variable in any way. The line b = a means "take the value from a and assign it to b" after that, b doesn't care what happens to a.
The number = int(string[count]) uses the value of count assigned outside the loop which is the first character index 0, it will never change outside the loop, so you will always get the original value appended which is the first character.
Using number = int(string[count]) inside the loop you are reassigning number to the value of the element at index count each time so you get a different part of the input string appended each time.
Once you enter the while loop any values you change that were defined outside of the loop will not change outside that loop, you must reassign the value inside the loop.
I get that you are a beginner. Here is a rewrite that should help you with some useful python idioms and constructs:
def numbers_in_lists(string):
numbers = [int(c) for c in string]
next_number = -1
final_list = []
for number in numbers:
if number > next_number:
final_list.append(number)
final_list.append([])
next_number = number
else:
final_list[-1].append(number)
final_list = [x for x in final_list if x != []]
print final_list
First, be suspicious when you have a while-loop and a counter. You can replace it with a for-loop that iterates over all the items.
Since this code operates on integers, not characters in a string, let's translate them all at once using a list comprehension:
numbers = [int(c) for c in string]
This creates a list that has all the characters translated to integers.
By setting next_number = -1, we ensure that all numbers in numbers will be greater. In particular, the first element will be greater.
When we find a number that exceeds our last maximum, next_number, we add number and a bucket to put succeeding numbers less than number into:
if number > next_number:
final_list.append(number)
final_list.append([])
next_number = number
That means when we add 5, final_list looks like this:
[5, []]
And when number is 4 and 3, they get added properly:
[5, [4]]
[5, [4, 3]]
How does that happen? This code does it:
else:
final_list[-1].append(number)
Here we do not append to final_list; we append to the last list in final_list, final_list[-1].
But what if our sequence was just 5? Then at the end of the loop, final_list would look like this:
[5, []]
In that case, we want to trim out all empty lists, so we do it like this:
final_list = [x for x in final_list if x != []]
This says, "make final_list into a list that has all elements of final_list except those that are empty lists."
Good luck with learning python. I hope you find it rewarding.

For Loop to While Loop using IN for while loops

I am quite new to Python 2.7 so I had a couple of questions regarding using for loops to while loops.
For example: I am writing this definition
def missingDoor(trapdoor,roomwidth,roomheight,step):
safezone = []
hazardflr = givenSteps(roomwidth,step,True)
safetiles = []
for m in hazardflr:
safetiles.append((m,step))
i = 0
while i < len(safetiles):
nextSafe = safetiles[i]
if knownSafe(roomwidth, roomheight, nextSafe[0], nextSafe[1]):
if trapdoor[nextSafe[0]/roomwidth][nextSafe[0]%roomwidth] is "0":
if nextSafe[0] not in safezone:
safezone.append(nextSafe[0])
for e in givenSteps(roomwidth,nextSafe[0],True):
if knownSafe(roomwidth, roomheight, e, nextSafe[0]):
if trapdoor[e/roomwidth][e%roomwidth] is "0" and (e,nextSafe[0]) not in safetiles:
safetiles.append((e,nextSafe[0]))
i += 1
return sorted(safezone)
I am trying to turn all the for loops to a while loops, so this is currently what I have written so far. I actually dont know if we say "While e in " works near the middle of the code. But using the while loop rules, will this code do the same as the for loop one?
safezone = []
hazardflr = givenSteps(roomwidth,step,True)
safetiles = []
m=0
while m < hazardflr:
safetiles.append((m,step))
i = 0
while i < len(safetiles):
nextSafe = safetiles[i]
if knownSafe(roomwidth, roomheight, nextSafe[0], nextSafe[1]):
if trapdoor[nextSafe[0]/roomwidth][nextSafe[0]%roomwidth] is "0":
if nextSafe[0] not in safezone:
safezone.append(nextSafe[0])
e=0
while e in givenSteps(roomwidth,nextSafe[0],True):
if knownSafe(roomwidth, roomheight, e, nextSafe[0]):
if trapdoor[e/roomwidth][e%roomwidth] is "0" and (e,nextSafe[0]) not in safetiles:
safetiles.append((e,nextSafe[0]))
e+=1
i += 1
m+=1
return sorted(safezone)
thanks for any advice or help!
No, your code isn't identical.
While they look similar, for item in list and while item in list will do wildly different things.
for item in list is a syntactic way of saying for every item in the list - do something with is.
while item in list is different - a while loop iterates as long as the condition is true. The condition in this case being item in list. It doesn't update the item each iteration and if you never change what item or list are, it might never terminate. Additionally, if any given item isn't in the list it may terminate prematurely.
If you want to iterate through a list and keep a count, using while is the wrong way to go about it. Use the enumerate() function instead.
enumerate() takes a list, and returns a list of tuples, with each item from the list in order with its index, like so:
for i,m in enumerate(hazardflr):
safetiles.append((m,step))
This small change means you no longer have to track your indices manually.
If you are iterating through every item in a list in Python - use for that's what it is designed to do.
It depends on exactly what givenSteps returns, but in general, no. for x in foo evaluates foo once and then assigns x to be each element of foo in turn. while x in foo: ... x += 1, on the other hand, evaluates foo on every iteration and will end early if foo is not a contiguous sequence. For example, if foo = [0, 1, 2, 5, 6], for will use every value of foo, but while will end after 2, because 3 is not in foo. while will also differ from for if foo contains any non-integral values or values below the starting value.
while aList:
m= hazardflr.pop()
# ...
should be roughly equivelent to your other loop

Recursion code in python

I'm new to python and trying to solve my homework... I'm trying to create a recursion function that takes a list of numbers [a, b, c....] and turns it to this list: [a, a+b, a+b+c, ....].
This is my code:
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
new_list=numbers
last=new_list[-1]
if numbers==[]:
return numbers
if len(numbers) == 1:
return numbers[0]
new_list.remove(last)
rec= rec_cumsum(new_list)
new_list.append(rec+last)
return last+rec
this works but because I used return for last+rec, I can't use return to get the list back (new_list). Please explain to me what did I do wrong... thanks!
Let's write some test cases and practice some test-driven development:
tests = [[], # Desired answer: []
[1], # [1]
[1,2], # [1, 3]
[1,2,3], # [1, 3, 6]
[1,2,1,3]] # [1, 3, 4, 7]
for t in tests:
print(rec_cumsum(t))
If we add this to your code and run it, we get:
last=new_list[-1]
IndexError: list index out of range
Why is this? Apparently -1 is an out-of-range index. Why wouldn't new_list have a -1 index?
Aha. That happens if new_list is empty. So we need to address the base case first. While we're at it, let's also use #MartijnPieters' suggestion:
if len(numbers) <= 1:
return numbers
to obtain
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) <= 1:
return numbers
new_list=numbers
last=new_list[-1]
new_list.remove(last)
rec = rec_cumsum(new_list)
new_list.append(rec[-1]+last)
return last+rec
Now run the test again. This time we get
return last+rec
TypeError: unsupported operand type(s) for +: 'int' and 'list'
So now Python is saying last is an int and rec is a list, and we can not add the two together.
Okay, rec should be a list since it is the return value of rec_cumsum(new_list). What should replace last+rec?
Let's think in terms of a concrete example. If rec is [a, a+b] then we want to return [a, a+b, a+b+c]. How do we form a+b+c?
How about adding the last element in rec with the last element of numbers:
rec[-1]+last
We want to append this to the end of rec:
rec.append(rec[-1]+last)
Let's make that change and see what happens. But while we're editing, let's also clean up some code we never use. We can delete new_list.append(rec[-1]+last):
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) <= 1:
return numbers
new_list=numbers
last=new_list[-1]
new_list.remove(last)
rec = rec_cumsum(new_list)
rec.append(rec[-1]+last)
return rec
Now our program returns
[]
[1]
[1, 3]
[1, 3, 6]
[2, 3, 4, 7]
Hurray, our program runs without errors. But wait... it returns the wrong results. Look at the last line.
rec_cumsum([1,2,1,3]) is returning [2,3,4,7] whereas the correct answer is [1,3,4,7]. Why is the first number wrong?
It has to do with new_list.remove(last). This command removes the first occurrence of last from new_list. We want to remove the last occurrence.
So instead, let's use
new_list = numbers[:-1]
So the program becomes:
def rec_cumsum(numbers):
''' Input: numbers - a list of numbers,
Output: a list of cumulative sums of the numbers'''
if len(numbers) <= 1:
return numbers
new_list=numbers[:-1]
last=numbers[-1]
rec = rec_cumsum(new_list)
rec.append(rec[-1]+last)
return rec
Run the tests. It works! Now it is a good practice to look back at our solution and see how it can be tightened up and made more elegant.
I see we used new_list and last as temporary variables. Do we really need them?
def rec_cumsum(numbers):
if len(numbers)<=1:
return numbers
result = rec_cumsum(numbers[:-1])
result.append(result[-1]+numbers[-1])
return result
Your function should always return a list; for the empty list case, an empty list, and for the case where there is only one element, a list with only one element.
But your code returns the one element, not a list with one element:
if len(numbers) == 1:
return numbers[0]
Change that to returning just numbers:
if len(numbers) == 1:
return numbers
You can combine this with the other end-state test:
if len(numbers) < 2:
return numbers
Next problem is that you are not creating a copy of a list when you create the variable new_list; you create a reference to the same list, you'd have to use a slice or create an explicit new list:
new_list = numbers[:]
If you are going to remove a value from that list anyway, you may as well adjust the slice a little, and put this after testing numbers (why do the work otherwise):
if len(numbers) < 2:
return numbers
new_list = numbers[:-1]
last = numbers[-1]
Nowhere in your code do you actually compute a sum; nothing is added to your numbers. You never add a to b, c, etc. Moreover, you seem to be focusing on the last number, while your assignment states you needed to sum the first value to the rest of the list.
And there is a pattern there. Not only do you add a to b, but the sum of a + b is added to c, and that sum is then added to d, etc. Let's make use of that:
def rec_cumsum(numbers, culmulated_sum=0):
if len(numbers) < 1:
return numbers
sum = numbers[0] + culmulated_sum
return [sum] + rec_cumsum(numbers[1:], sum)
Note that I don't even bother storing a copy of numbers now; may as well just pass it to the next recursion as a slice of everything but the first element. We also use the first element from numbers to create our sum (numbers[0]).
Also, we now pass along the culmulative sum so far, starting at 0; and that means we need to change the end condition of the recursive function; we are essentially adding [0] to the start of the list, and we want to make sure we sum that with the next element always.
This now does what you need:
>>> rec_cumsum([5, 1, 10, 2, 3])
[5, 6, 16, 18, 21]

Delete an item from a list

Hey, I was trying to delete an item form a list (without using set):
list1 = []
for i in range(2,101):
for j in range(2,101):
list1.append(i ** j)
list1.sort()
for k in range(1,len(list1) - 1):
if (list1[k] == list1[k - 1]):
list1.remove(list1[k])
print "length = " + str(len(list1))
The set function works fine, but i want to apply this method. Except I get:
IndexError: list index out of range
on the statement:
if (list1[k] == list1[k - 1]):
Edited to add
(Thanks to Ned Batchelder) the working code is:
list1 = []
for i in range(2,101):
for j in range(2,101):
list1.append(i ** j)
list1.sort()
k = 0
while k < len(list1) - 1: # while loop instead of for loop because "The range function is evaluated once before the loop is entered"
k += 1
if (list1[k] == list1[k - 1]):
list1.remove(list1[k])
list1.sort()
k -= 1 # "If you find a duplicate, you don't want to move onto the next iteration, since you'll miss potential runs of more than two duplicates"
print "length = " + str(len(list1))
Your code doesn't work because in your loop, you are iterating over all the indexes in the original list, but shortening the list as you go. At the end of the iteration, you will be accessing indexes that no longer exist:
for k in range(1,len(list1) - 1):
if (list1[k] == list1[k - 1]):
list1.remove(list1[k])
The range function is evaluated once before the loop is entered, creating a list of all the indexes in the list. Each call to remove shortens the list by one, so if you remove any elements, you're guaranteed to get your error at the end of the list.
If you want to use a loop like this, try:
k = 1
while k < len(list1):
if list1[k] == list1[k-1]:
del list1[k]
else:
k += 1
I fixed a few other things:
You don't need parentheses around the condition in Python if statements.
If you find a duplicate, you don't want to move onto the next iteration, since you'll miss potential runs of more than two duplicates.
You want to start from index 1, not zero, since k=0 will access list1[-1].
It looks as if you're trying to uniquify a list (clarification would be awesome) so take a look here: http://www.peterbe.com/plog/uniqifiers-benchmark
There is also this question here on SO: In Python, what is the fastest algorithm for removing duplicates from a list so that all elements are unique *while preserving order*?
Instead of removing items Write a list comprehension of the things you want in the new list:
list1[:] = [list1[k] for k in range(1,len(list1) - 1)
if not list1[k] == list1[k - 1] ]
Your method breaks because you remove items from the list. When you do that, the list becomes shorter and the next loop iteration has skipped a item. Say you look at k=0 and L = [1,2,3]. You delete the first item, so L = [2,3] and the next k=1. So you look at L[1] which is 3 -- you skipped the 2!
So: Never change the list you iterate on
You can use del :
l = [1, 2, 3, 4]
del l[2]
print l
[1, 2, 4]

Categories