Why am I getting out of range error? - function

I'm building a function to extract all negatives from the list xs. Then I'm appending those negatives to a list negatives, and adding list negatives to list new_home, which may or may not already have values to it. The function was working before I added xs.pop(num). Why is it now out of range?
Here is the code:
def extract_negatives(xs,new_home=None):
negatives=[]
if new_home==None:
for num in range(len(xs)):
if xs[num] <0:
negatives.append(xs[num])
xs.pop(num)
return negatives
else:
for num in range(len(xs)):
if xs[num] <0:
new_home.append(xs[num])
xs.pop(num)
return new_home.append(negatives)

As stated, you are mutating list passed to the function and hence index is getting messed up.
If you must delete from passed list then one idea is to delete at the end of function just before you returned result. That way mutation wont affect indexing.
Also , I don't understand why you have if and else both looking for xs<0 . I cleaned up your function and got it working.
EDIT1 -Working Code
def extract_negatives(xs,new_home):
negatives=[]
for num in range(len(xs)):
if xs[num] <0:
negatives.append(xs[num])
new_home = new_home + negatives
for i in negatives:
xs.remove(i)
return new_home
new_home=[-9,-11,]
xs = [ 2 ,-3, 4, -5, 6, -7]
new_home = extract_negatives(xs,new_home)
print new_home
Output
>>>
[-9, -11, -3, -5, -7]
>>> xs
[2, 4, 6]

Related

Csv reader PyQt5 [duplicate]

I've an iterable list of over 100 elements. I want to do something after every 10th iterable element. I don't want to use a counter variable. I'm looking for some solution which does not includes a counter variable.
Currently I do like this:
count = 0
for i in range(0,len(mylist)):
if count == 10:
count = 0
#do something
print i
count += 1
Is there some way in which I can omit counter variable?
for count, element in enumerate(mylist, 1): # Start counting from 1
if count % 10 == 0:
# do something
Use enumerate. Its built for this
Just to show another option...hopefully I understood your question correctly...slicing will give you exactly the elements of the list that you want without having to to loop through every element or keep any enumerations or counters. See Explain Python's slice notation.
If you want to start on the 1st element and get every 10th element from that point:
# 1st element, 11th element, 21st element, etc. (index 0, index 10, index 20, etc.)
for e in myList[::10]:
<do something>
If you want to start on the 10th element and get every 10th element from that point:
# 10th element, 20th element, 30th element, etc. (index 9, index 19, index 29, etc.)
for e in myList[9::10]:
<do something>
Example of the 2nd option (Python 2):
myList = range(1, 101) # list(range(1, 101)) for Python 3 if you need a list
for e in myList[9::10]:
print e # print(e) for Python 3
Prints:
10
20
30
...etc...
100
for i in range(0,len(mylist)):
if (i+1)%10==0:
do something
print i
A different way to approach the problem is to split the iterable into your chunks before you start processing them.
The grouper recipe does exactly this:
from itertools import izip_longest # needed for grouper
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
You would use it like this:
>>> i = [1,2,3,4,5,6,7,8]
>>> by_twos = list(grouper(i, 2))
>>> by_twos
[(1, 2), (3, 4), (5, 6), (7, 8)]
Now, simply loop over the by_twos list.
You can use range loops to iterate through the length of mylist in multiples of 10 the following way:
for i in range(0,len(mylist), 10):
#do something

ValueError: The truth value of a Series is ambiguous in multiple if condition

I want to apply multiple if conditions on a series and get the results of my function.
I have the following dictionary:
cardinal_Temp = ["Tbas_veg", "Topt1_veg", "Topt2_veg","Tmax_veg"]
wheat_CardTemp_vegetative = [4, 22, 28, 38]
Veg_CardTemp= dict(zip(cardinal_Temp, wheat_CardTemp_vegetative))
And a daily temperature list with more than 400 values as:
df= pd.DataFrame(Date_MeanTemp, columns=["Date","Tmean"])
I wrote the below script to compute my function as:
def Temfunction(Tmean):
if ((Veg_CardTemp["Tbas_veg"]<(df["Tmean"])) and ((df["Tmean"])<Veg_CardTemp["Topt1_veg"])).any():
return [((df["Tmean"])-Veg_CardTemp["Tbas_veg"])/(Veg_CardTemp["Topt1_veg"]-Veg_CardTemp["Tbas_veg"])]
elif ((Veg_CardTemp["Topt1_veg"]<=(df["Tmean"])) and ((df["Tmean"])<=Veg_CardTemp["Topt2_veg"])).any():
return 1
elif ((Veg_CardTemp["Topt2_veg"]<(df["Tmean"])) and ((df["Tmean"])<Veg_CardTemp["Tmax_veg"])).any():
return [(Veg_CardTemp["Tmax_veg"]-df["Tmean"])/(Veg_CardTemp["Tmax_veg"]-Veg_CardTemp["Topt2_veg"])]
elif (((df["Tmean"])<=Veg_CardTemp["Tbas_veg"]) or ((df["Tmean"])>=Veg_CardTemp["Tmax_veg"])).any():
return 0
function = np.vectorize(Temfunction)
Tempfunction = function(df["Tmean"])
print("final Tempfunc:", Tempfunction)
I run to ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
I tried to make a function to compute a temperature function between 0 and 1, for each day in "df" list.

csv empty strings handling and values appending

With a csv of ~50 rows (stars) and ~30 columns (name, magnitudes and distance), that has some empty string values (''), I am trying to do two things in which all the help so far hasn't been useful. (1) I need to parse empty strings as 0.0, so I can (2) append each row in a list of lists (what I called s).
In other words:
- s is a list of stars (each one has all its parameters)
- d is a particular parameter for all the stars (distance), which I obtain correctly.
Big issue is with s. My try:
with open('stars.csv', 'r') as mycsv:
csv_stars = csv.reader(mycsv)
next(csv_stars) #skip header
stars = list(csv_stars)
s = [] # star
d = [] # distances
for row in stars:
row[row==''] = '0'
s.append(float(row)) #stars
d.append(arcsec*AU*float(row[30]))
I can't think of a better syntax, and so I get the error
s.append(float(row)) # stars
TypeError: float() argument must be a string or a number
From s I would obtain later the magnitudes for all the stars, separately. But first things first...
#cwasdwa Please look at below code. it will give you an idea. I am sure there might be better way. This solution is based on what I have understood from your code.
with open('stars.csv', 'r') as mycsv:
csv_stars = csv.reader(mycsv)
next(csv_stars) #skip header
stars = list(csv_stars)
s = [] # star
d = [] # distances
for row in stars:
newRow = [] #create new row array to convert all '' to 0.0
for x in row:
if x =='':
newRow.append(0.0)
else:
newRow.append(x)
s.append(newRow) #stars
if row[30] == '':
value = 0.0
else:
value = row[30]
d.append(arcsec*AU*float(value))

Egg dropping in worst case

I have been trying to write an algorithm to compute the maximum number or trials required in worst case, in the egg dropping problem. Here is my python code
def eggDrop(n,k):
eggFloor=[ [0 for i in range(k+1) ] ]* (n+1)
for i in range(1, n+1):
eggFloor[i][1] = 1
eggFloor[i][0] = 0
for j in range(1, k+1):
eggFloor[1][j] = j
for i in range (2, n+1):
for j in range (2, k+1):
eggFloor[i][j] = 'infinity'
for x in range (1, j + 1):
res = 1 + max(eggFloor[i-1][x-1], eggFloor[i][j-x])
if res < eggFloor[i][j]:
eggFloor[i][j] = res
return eggFloor[n][k]print eggDrop(2, 100)
```
The code is outputting a value of 7 for 2eggs and 100floors, but the answer should be 14, i don't know what mistake i have made in the code. What is the problem?
The problem is in this line:
eggFloor=[ [0 for i in range(k+1) ] ]* (n+1)
You want this to create a list containing (n+1) lists of (k+1) zeroes. What the * (n+1) does is slightly different - it creates a list containing (n+1) copies of the same list.
This is an important distinction - because when you start modifying entries in the list - say,
eggFloor[i][1] = 1
this actually changes element [1] of all of the lists, not just the ith one.
To instead create separate lists that can be modified independently, you want something like:
eggFloor=[ [0 for i in range(k+1) ] for j in range(n+1) ]
With this modification, the program returns 14 as expected.
(To debug this, it might have been a good idea to write out a function to pring out the eggFloor array, and display it at various points in your program, so you can compare it with what you were expecting. It would soon become pretty clear what was going on!)

find function matlab in numpy/scipy

Is there an equivalent function of find(A>9,1) from matlab for numpy/scipy. I know that there is the nonzero function in numpy but what I need is the first index so that I can use the first index in another extracted column.
Ex: A = [ 1 2 3 9 6 4 3 10 ]
find(A>9,1) would return index 4 in matlab
The equivalent of find in numpy is nonzero, but it does not support a second parameter.
But you can do something like this to get the behavior you are looking for.
B = nonzero(A >= 9)[0]
But if all you are looking for is finding the first element that satisfies a condition, you are better off using max.
For example, in matlab, find(A >= 9, 1) would be the same as [~, idx] = max(A >= 9). The equivalent function in numpy would be the following.
idx = (A >= 9).argmax()
matlab's find(X, K) is roughly equivalent to numpy.nonzero(X)[0][:K] in python. #Pavan's argmax method is probably a good option if K == 1, but unless you know apriori that there will be a value in A >= 9, you will probably need to do something like:
idx = (A >= 9).argmax()
if (idx == 0) and (A[0] < 9):
# No value in A is >= 9
...
I'm sure these are all great answers but I wasn't able to make use of them. However, I found another thread that partially answers this:
MATLAB-style find() function in Python
John posted the following code that accounts for the first argument of find, in your case A>9 ---find(A>9,1)-- but not the second argument.
I altered John's code which I believe accounts for the second argument ",1"
def indices(a, func):
return [i for (i, val) in enumerate(a) if func(val)]
a = [1,2,3,9,6,4,3,10]
threshold = indices(a, lambda y: y >= 9)[0]
This returns threshold=3. My understanding is that Python's index starts at 0... so it's the equivalent of matlab saying 4. You can change the value of the index being called by changing the number in the brackets ie [1], [2], etc instead of [0].
John's original code:
def indices(a, func):
return [i for (i, val) in enumerate(a) if func(val)]
a = [1, 2, 3, 1, 2, 3, 1, 2, 3]
inds = indices(a, lambda x: x > 2)
which returns >>> inds [2, 5, 8]
Consider using argwhere in Python to replace MATLAB's find function. For example,
import numpy as np
A = [1, 2, 3, 9, 6, 4, 3, 10]
np.argwhere(np.asarray(A)>=9)[0][0] # Return first index
returns 3.
import numpy
A = numpy.array([1, 2, 3, 9, 6, 4, 3, 10])
index = numpy.where(A >= 9)
You can do this by first convert the list to an ndarray, then using the function numpy.where() to get the desired index.