Find the smallest element in a list - python

I would like to find the smallest value of list a. I know that there is a function like min() to find the value but I would like do it work with a for-loop.
I get the error Index out of range with the if-Statement, but I don't know why.
a = [18,15,22,25,11,29,31]
n = len(a)
tmp = a[0]
for i in a:
if(a[i] < tmp):
tmp = a[i]
print(tmp)

When you iterate over a list in Python (for e in l:), you do not iterate over the indices but over the elements directly. So you should write:
for e in a:
if(e < tmp):
tmp = e
print(tmp)

As already said, you mixed iteration over elements and looping over indexes. The solution for iteration over elements was already presented, so for completeness I would like to write the other solution:
a = [18,15,22,25,11,29,31]
n = len(a)
tmp = a[0]
for i in range(n):
if(a[i] < tmp):
tmp = a[i]
print(tmp)
Edit: changed xrange to range as per comment bellow.

Related

Using list comprehension to calculate the sum of all list elements

Don't know if I'm just being stupid right now but I'm trying to convert a list of int to one int. The problem is that I am trying to do it with just a list comprehension but I'm failing every time
class MathStuff():
def add_stuff(self, *stuff):
items = 0
numbers = (i for i in stuff)
items += [i for i in e]
#trying to do "for i in (i for i in stuff)" but assign it to a variable
I've tried multiple ways to do this without a "for loop" but I'm hitting a brick wall with my google searching.
If you have a list of numbers, l, and you don't want to use sum. I suppose you could do the usual:
l = range(1, 100)
s = 0
for i in l:
s += i
Or a more functional approach.
from operator import add
from functools import reduce
l = range(1, 100)
reduce(add, l)
I don't see how comprehensions could help you solve this however.
If you really want to use list comprehension, you can make a new list with an equal number of list entries as your input data. Then, flatten the list, and finally, use its length as the sum. You have to do this for positive and negative values separately, though:
long_pos = [[i for i in range(l)] for l in stuff if l > 0]
long_neg = [[i for i in range(abs(l))] for l in stuff if l < 0]
flat_pos = [i for sub in long_pos for i in sub]
flat_neg = [i for sub in long_neg for i in sub]
items = len(flat_pos) - len(flat_neg)

What is the correct loop range

I want to delete some array from list. But I'm using wrong range.
At start the range is correct.
This should work, if string in variable result[b][2:3] then delete result[b]
for b in range(len(result)):
if 'FillLevel' in result[b][2:3]:
del result[b]
After that I have error: IndexError: list index out of range
I want to find this string and delete whole line (array):
V;4;FillLevel[1];CPUA.DB1610.0,I0,64;RW
V;4;FillLevel[2];CPUA.DB1610.0,I;RW
V;4;FillLevel[5];CPUA.DB1610.6,I;RW
V;4;FillLevel[6];CPUA.DB1610.8,I;RW
V;4;FillLevel[11];CPUA.DB1610.18,I;RW
Why this code:
print(result[4][2:3])
print(result[5][2:3])
print(result[6][2:3])
print(result[7][2:3])
print(result[8][2:3])
print(result[9][2:3])
print(result[10][2:3])
b = 0
while b < len(result):
if 'FillLevel' in result[b][2:3]:
del result[b]
del adress[b]
print('yes')
b += 1
Showing only once 'yes' ?
['FillLevel']
['FillLevel[1]']
['FillLevel[2]']
['FillLevel[3]']
['FillLevel[4]']
['FillLevel[5]']
['FillLevel[6]']
yes
The issue is that del result[b] changes the composition (and the length of) result, thereby interfering with your loop.
Perhaps the easiest way to fix this is by rephrasing your code as a list comprehension:
result = [r for r in result if 'FillLevel' not in r[2:3]]
Alternatively, you could fix it by iterating in reverse:
for b in range(len(result) - 1, -1, -1):
if 'FillLevel' in result[b][2:3]:
del result[b]
Let's say there are 10 items in the list.
Half-way through you delete one of the items; now there are 9 items in the list.
In the last cycle, your loop asks for the tenth item. My guess is that's where the index error is happening (though it could be due to the [2:3] call as well, depending on the contents of your list)
A more pythonic solution would be
result = [val for val in result if 'FillLevel' not in val[2:3]]
If you want to preserve the same list and parse it in the strait order you can use a while loop which evaluate the len(result) in each iteration
b = 0
while b < len(result) :
if 'FillLevel' in result[b][2:3]:
del result[b]
b += 1
for first
- it's mach easyer to iterate by list withot getting length, probably you are got an error coz length of list is changing during loop
for second
- you are trying to check 'FillLevel' in slice of string. slice return one character
- try to not midify your list but make new one with filtered items
like this:
new_list = []
for b in result:
if 'FillLevel' not in b:
new_list.append(b)
or check about List Comprehensions and type this:
[i for i in result if 'FillLevel' not in i]

How to skip empty lists when iterating over lists within a list?

Take the following code as an example:
a = [['James Dean'],['Marlon Brando'],[],[],['Frank Sinatra']]
n = 0
for i in a:
print a[n][0]
n = n + 1
I seem to be getting an error with the index value:
IndexError: list index out of range
How do I skip over the empty lists within the list named a?
Simple:
for i in a:
if i:
print i[0]
This answer works because when you convert a list (like i) to a boolean in an if statement like I've done here, it evaluates whether the list is not empty, which is what you want.
You can check if the list is empty or not, empty lists have False value in boolean context -
for i in a:
if i:
print a[n][0]
n = n + 1
Also, instead of using n separately, you can use the enumerate function , which returns the current element as well as the index -
for n, i in enumerate(a):
if i:
print a[n][0] # though you could just do - print i[0]
You could either make a test, or catch the exception.
# Test
for i in a:
if a[n]:
print a[n][0]
n = n + 1
# Exception
for i in a:
try:
print a[n][0]
except IndexError:
pass
finally:
n = n + 1
You could even use the condensed print "\n".join(e[0] for e in a if e) but it's quite less readable.
Btw I'd suggest using using for i, element in enumerate(a) rather than incrementing manually n
Reading your code, I assume you try to get the first element of the inner list for every non empty entry in the list, and print that. I like this syntax:
a = [['James Dean'],['Marlon Brando'],[],[],['Frank Sinatra']]
# this filter is lazy, so even if your list is very big, it will only process it as needed (printed in this case)
non_empty_a = (x[0] for x in a if x)
for actor in non_empty_a : print (actor)
As mentioned by other answers, this works because an empty list is converted to False in an if-expression

Python-Merge sort difficulties

I attempted to implement a merge sort, here is my code:
def mergeSort(array):
result=[]
n=len(array)
if n==1:
result=array
else:
a=round(n/2)
first=mergeSort(array[0:a])
second=mergeSort(array[a:n])
for i in range(len(first)):
for j in range(len(second)):
if first[i]<second[j]:
result.append(first[i])
i=i+1
else:
result.append(second[j])
j=j+1
return result
a=[5,4,1,8,7,6,2,3]
b=mergeSort(a)
print(b)
Unfortunately, the result turns out to be [1]. What is wrong with my function?
A number of things...
Firstly, this is a recursive function, meaning you cannot create a list within the function, as you did here:
result=[]
This will simply reset your list after every recursive call, skewing your results. The easiest thing to do is to alter the list that is passed as a parameter to merge sort.
Your next problem is that you have a for loop within a for loop. This will not work because while the first for loop iterates over first, the second for loop will iterate over second for every increment of i, which is not what you want. What you need is to compare both first and second and extract the minimum value, and then the next minimum value, and so on until you get a sorted list.
So your for loops need to be changed to the following:
while i < len(first) and j < len(second):
Which leads me to final problem in your code. The while loop will exit after one of the conditions are met, meaning either i or j (one or the other) will not have reached len(first) or len(second). In other words, there will be one value in either first or second that is unaccounted for. You need to add this unaccounted value to your sorted list, meaning you must implement this final excerpt at the end of your function:
remaining = first if i < j else second
r = i if remaining == first else j
while r < len(remaining):
array[k] = remaining[r]
r = r + 1
k = k + 1
Here r represents the index value where the previous while loop broke off. The while loop will then iterate through the rest of the remaining values; adding them to the end of your sorted list.
You merge sort should now look as follows:
def mergeSort(array):
if len(array)==1:
return array
else:
a=round(len(array)/2)
first=mergeSort(array[:a])
second=mergeSort(array[a:])
i = 0
j = 0
k = 0
while i < len(first) and j < len(second):
if first[i]<second[j]:
array[k] = first[i]
i=i+1
k=k+1
else:
array[k] = second[j]
j=j+1
k=k+1
remaining = first if i < j else second
r = i if remaining == first else j
while r < len(remaining):
array[k] = remaining[r]
r += 1; k += 1
return array
I tried to not alter your code as much as possible in order to make it easier for you to understand. However, if your difficulty in understanding what I did persists, try de-bugging your merge sort using multiple print statements so that you can follow the function's progress and see where it goes wrong.

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