The assignment:
Write a function called splitList(myList, option) that takes, as input, a list and an option, which is either 0 or 1. If the value of the option is 0, the function returns a list consisting of the elements in myList that are negative, and if the value of the option is 1, the function returns a list consisting of the elements in myList that are even.
I know how to determine if a number is even and if a number is negative. I'm struggling with how to return a new list of negative or even numbers based on "option"
This is what I've gotten so far:
def splitList(myList):
newlist = []
for i in range(len(myList)):
if (myList[i]%2 == 0):
newlist.append(myList [i])
return newlist
This program gives the following error:
Traceback (most recent call last): File "<string>", line 1, in <fragment>
builtins.TypeError: splitList() takes exactly 1 positional argument (4 given)
As I mentioned in my comment, you should standardize your indentation: four spaces is Python standard. You can usually set your editor to insert four spaces instead of tabs (don't want to mix tabs with spaces, either).
As to your actual question: try writing three total functions: one that returns all the negative values, one that returns even values, and one that calls the appropriate function based on option.
def splitlist(myList, option):
if option == 1:
return get_even_elements(myList)
elif option == 0:
return get_negative_elements(myList)
def get_even_elements(myList):
pass # Implementation this method here.
def get_negative_elements(myList):
pass # Implementation this method here.
# Test it out!
alist = [-1, 2, -8, 5]
print splitlist(alist, 0)
print splitlist(alist, 1)
Henry Keiter's comment was correct. Just add one space before newlist.append(myList [i]) and it works just fine.
Alternatively, if your teacher lets you, you could use tabs instead of spaces to avoid this problem altogether (just make sure you don't use both in the same file).
def splitList(myList, option):
return [i for i in myList if i<0] if option==0 else [i for i in myList if i>0]
# test
>>> myList=[2, 3, -1, 4, -7]
>>> splitList(myList, 0)
[-1, -7]
>>> splitList(myList, 1)
[2, 3, 4]
>>>
I tried your code as-is and I did not get any errors when I passed in a list of positive integers, so I don't know why your program is 'crashing', so I suspect something else is interfering with your debugging. (Although, as others have said, you really should use the same number of spaces at every indent level.)
Here's what I entered:
def splitList(myList):
newlist = []
for i in range(len(myList)):
if (myList[i]%2 == 0):
newlist.append(myList [i]) # Only 3-space indent here
return newlist
print splitList([1, 2, 3, 4, 5])
When I run it:
[2, 4]
Can you show how you're invoking the method and the exact error message?
My previous answer was incorrect, and I really should have tested before I opened my mouth... Doh!!! Live and learn...
edit
your traceback is giving you the answer. It is reading the list as an args list. Not sure if there is a super pythonic way to get around it, but you can use named arguments:
splitList(myList=yourList)
OR
splitList(myList=(1,2,3))
OR
splitList(myList=[1,2,3])
But your problem is really probably
splitList(1,2,3,4) # This is not a list as an argument, it is a list literal as your 'args' list
Which can be solved with:
splitList([1,2,3,4])
OR
splitList((1,2,3,4))
Is this the traceback you get?
Traceback (most recent call last):
File "pyTest.py", line 10, in <module>
print splitList(aList,1)
TypeError: splitList() takes exactly 1 argument (2 given)
The error is most likely telling you the issue, this would be that the method only takes one argument, but I tried passing in two arguments like your requirements state.
edit
Can you show the code where you are calling the splitList method?
this was incorrect
myList [i]
is your problem, you can't have a space in there. python is VERY VERY VERY strict about syntax
since people seemed to think they should downvote me, let me explain:
by having that space, you effectively said myList (which is a list), and [i], which is a list literal with the value of 'i' at index 0....
so you are passing two variables (one actual variable and one literal) into the append method, NOT separated by a comma, which will not work.
Related
L=[1,2,3]
print(L[L[2]])
What will be the output?
I am a beginner to python and I am confused by this specific thing in List. I am not understanding what this means.
I 'm going to explain with this list (because you will get IndexError with current list):
L = [1, 2, 3, 4, 5]
print(L[L[2]])
First, Python sees the print() function, in order to call this function, Python has to know it's arguments. So it goes further to evaluate the argument L[L[2]].
L is a list, we can pass an index to the bracket to get the item at that index. So we need to know the index. We go further and calculate the expression inside the first []. It's L[2].
Now we can easily evaluate the expression L[2]. The result is 3.
Take that result and put it instead of L[2]. our full expression is print(L[3]) at the moment.
I think you get the idea now...
From inside to the outside:
step1 -- > print(L[L[2]])
step2 -- > print(L[3])
step3 -- > print(4)
Here what you are doing is, you are getting the value at 2 which should be 3, because python starts from 0 and goes up. So after that the interior braces should be done, and then you find the index at 3 which is too big. Because the indexes only go up to 2, and if I say I had three numbers, and you ask me what the fourth number is, that wouldn't make sense right? So that is the same thing. This would result in an error.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
This means that you are trying to get a value that does not exist. I hope this makes it clear.
L[L[2]] becomes L[3], since L[2] is equal to 3. Then, since there are three elements in L, and indexing starts at 0 in Python, this would result in an IndexError.
My code is giving me a name not defined error:
Traceback (most recent call last): File "split.py", line 22, in print(even)
NameError: name 'even' is not defined
Here's the instructions, and what I have written.. if someone could point me in the right direction it would be appreciated.
instructions: We are passing in a list of numbers. You need to create 2 new lists in your chart, then:
put all odd numbers in one list
put all even numbers in the other list
output the odd list first, the even list second
Tip: you should use the modulo operator to decide whether the number is odd or even. We provided a function for you to call that does this.
Don’t forget to define the 2 new lists before you start adding elements to them.
# Get our input from the command line
import sys
numbers = sys.argv[1].split(',')
for i in range(0,len(numbers)):
numbers[i]= int(numbers[i])
def isEven(n) :
return ((n % 2) == 0)
def Split(numbers):
even = [ ]
odd = [ ]
for i in numbers:
if i == isEven:
even.append(i)
else:
odd.append(i)
print(even) # <= error here: NameError: name 'even' is not defined
print(odd)
First of all, welcome to Python!
There are multiple problems with your code.
First, in Split(), you run if i == isEven:. This checks whether i is the same as isEven, which it is not. isEven is a function, and i is an integer, so they can never be the same. Since you're trying to check whether i is even, you have to pass i into isEven(). Then, isEven outputs a boolean, saying whether the number is even or not:
if isEven(i):
That checks whether i is even.
Secondly, variables have something called scope. Scope is where the variable is defined and where it can be accessed from. Because you define even and odd in Split(), they can only be accessed from the code inside the function. That's why you can append things to it inside of Split(), but not print() it at the end. To fix this, you have to return the variables even and odd.
As well, functions have to be called first before the code inside of them is run. Right now, the function Split() is defined, but never ran, so even and odd can't exist, even if you return them.
Just like isEven() returned a boolean that said whether a number was even or odd, and you were able to access it in Split(), you can return the two lists from it, allowing you to access them and print them. To do this, add this at the end:
return even, odd
Now, whenever you call Split(), it will return a tuple of the two lists, that you can then access the individual elements and print:
output = Split(numbers) # Get the output from Split()
even = output[0] # Get the first element of the output, the evens
odd = output[1] # Get the second element of the output, the odds
print(even) # Print even
print(odd) # Print odd
If you still don't fully understand why this would work, and why your current code returns an error, I'd advise you to ask your teacher about it, as they can explain it the best to you.
You declare even and odd in the function's local scope. try returning the two lists in a tuple or something.
def Split(numbers):
even = [ ]
odd = [ ]
for i in numbers:
if i == isEven:
even.append(i)
else:
odd.append(i)
rerturn (odd, even)
This is not the very code you should be using, but I hope you can figure it out from here :)
My Python script opens 2 threading.Threads() with the following functions :
Stuff() : function appending stuff to a list (global var) if stuff happens in a big loop.
Monitor() : function displaying the last item added to the list every second with additional info.
The purpose of these 2 threads is that Stuff() contains a loop optimized to be very fast (~ 200 ms / iteration) so printing from inside would be pointless. Monitor()takes care of the output instead.
At the beginning, I set list = [], then start the threads. Inside Monitor() I get the last item of the list with list[-1] but if no stuff happend before, the list is still empty and the Monitor() raises an IndexError: list index out of range.
Is there a simple way (no try or if not list) to display None instead of an error if the list is empty ?
Here's a way, although it looks odd:
(list or [None])[-1]
I find this more readable than #Alex's answer
lst = [1, 3, 2]
print None if not lst else lst[-1]
Edit: Though must admit, it is the first time I encountered that usage. Always thought those expressions returned bool type :)
You can use it also like this:
[1, 2, 3, 4][-1:] -> [4]
[][-1:] -> []
[][-1:] or None -> None
I'm trying to debug some code for someone, and have run into a rather odd scenario. The purpose of the code is to search for duplicates in a given list and then return a list with no duplicates. (Note, the person writing the code chose to simply delete the duplicates from the list, when I personally would just add each value to a new list. However, I am still intrigued by the oddity). The code is as follows:
def remove_duplicates(duplicates):
duplicates_del = duplicates
for i in duplicates_del:
if duplicates_del.count(i) > 1:
duplicates_del.remove(i)
return duplicates_del
remove_duplicates([3, 3, 3, 3, 3, 3])
When run, the code will return [3, 3, 3] and after some debugging, I've found that the code will work fine until duplicates_del.count(i) is equal to 4. On the next round, it will completely skip everything inside the for statement and go directly to the return statement, resulting in the answer that we get.
I have learned that changing the if statement to while duplicates_del.count(i) > 1: will make the code run flawlessly.
I've looked into the code for the debugger, and learned that there is a breakpoint class that can ignore counts. Is the if statement somehow triggering this breakpoint, or is there another reason why the code doesn't run fully with an if statement instead of a while loop?
The reason this is happening is because you're iterating over a list while you're removing items. This will mostly always result in unexpected results. Take a look at:
L = [1, 2, 3, 4, 5]
for item in L:
if item == 1 or item == 2 or item == 3:
L.remove(item)
print L
The output is:
[2, 4, 5]
Notice that 2 was never removed. If we print item in each loop, we get:
1
3
5
After python removes 1, the order of the list will change, and 2 won't necessarily be the next item in the loop (in fact, 3 is). Notice how 4 is also skipped.
To avoid such behaviour, you must iterate over a copy of the list. Sadly, what you did was not making a copy. Doing duplicates_del = duplicates will make both objects reference the same identity, so changing an element in one will change it in the other.
You should do this:
def remove_duplicates(duplicates):
for i in duplicates[:]: # Creates a copy of the list
if duplicates.count(i) > 1:
duplicates.remove(i)
return duplicates
You are deleting from the list as you loop over it.
Usually, this means that the item following one that is deleted is skipped over.
In this case remove is removing the first matching element each time, so the entire list is being shifted down. The list iterator doesn't see that the list has changed, so increments to the next item.
This is probably a very straight forward question but would love a simple explanation as to the why?
The below code requires a list in order to obtain a random card.
import random
card = random.choice (["hearts", "clubs", "frogs"])
I am puzzled as to why it requires a list and why I cannot do this.
import = random
card = random.choice("hearts" , "clubs", "frogs")
I'm fine that I can't do it I just would like to know why?
Because of Murphy's law: anything that can be done the wrong way will be done the wrong way by someone, some day. Your suggested API would require
random.choice(*lst)
when the values to choose from are in the list (or other sequence) lst. When someone writes
random.choice(lst)
instead, they would always get lst back instead of an exception. The Python principle that "explicit is better than implicit" then dictates that we have to type a few extra characters.
(Admitted, the result of random.choice("foobar") pointed out by others may be surprising to a beginner, but once you get used to the language you'll appreciate the way that works.)
The issue is that you're calling random.choice with 3 parameters, not a single parameter with 3 elements. Try random.choice(('one', 'two', 'three')) for instance.
Any sequence with a length and a suitable __getitem__ (for indexing) will do - since it picks a number between 0 and len(something) to choose the element.
So you could use a tuple instead if you so wanted.
because, the first snippet
["hearts","clubs","frogs"]
sends only one argument to the function (a list)
while the second one sends three strings to the function. The function choice is equipped to take only a single argument. So, you have to send it as a list or anything that can be indexed, so that it chooses a random index to return the value
random.choice will work for any sequence that supports indexing.
>>> random.choice("foobar") #string
'o'
>>> random.choice(("foo","bar","spam")) #tuple
'spam'
>>> random.choice(["foo","bar","spam"]) #list
'spam'
Will not work for sets:
>>> random.choice({"foo","bar","spam"})
Traceback (most recent call last):
File "<ipython-input-313-e97c3088a7ef>", line 1, in <module>
random.choice({"foo","bar","spam"})
File "/usr/lib/python2.7/random.py", line 274, in choice
return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty
TypeError: 'set' object does not support indexing
In random.choice("hearts" , "clubs", "frogs") you actually passed three arguments to choice, while random.choice expects only one parameter and that too must support indexing.
But random.choice can work for dict if the dict has numeric keys(that are between 0 to len(dict)-1), as internally it does something like this:
dic[int(random() * len(seq))]
Example:
>>> dic = dict(zip([1, 2, 3, 4, 5, 6], "abcdef"))
>>> random.choice(dic)
'b'
>>> random.choice(dic)
'd'
>>> random.choice(dic)
'd'
>>> random.choice(dic) #fails as 0 was not found in dic
Traceback (most recent call last):
File "<ipython-input-366-5cfa0e5f2911>", line 1, in <module>
random.choice(dic)
File "/usr/lib/python2.7/random.py", line 274, in choice
return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty
KeyError: 0
There are several good answers above about why random.choice is implemented as it is, and why it's actually what you probably want.
You can wrap it yourself easily enough, if you want to be able to call choice with arbitrary numbers of arguments:
import random
def random_choice_of_arbitrary_args(*args):
return random.choice(args)
Of course you would probably name it something more concise.
This does have the following surprising behavior:
>>> random_choice_of_arbitrary_args([1, 2, 3])
[1, 2, 3]
Which is because you're ultimately telling random.choice to give you a random element of a sequence with one element. So a better implementation might be:
import random
def my_choice(*args):
if len(args) == 1:
return random.choice(args[0])
else:
return random.choice(args)
Have a look at the implementation. It picks a random number from 0 to len(input_sequence) and then uses that index to choose a random item.
Perhaps a better answer is because the documentation says that the input has to be a sequence.
Put simply, because that's not how the random.choice function was defined. My guess is that the decision was made just because accepting a single iterable argument is a cleaner practice than just a variable number of arbitrary arguments.
Therefore defining the function like this:
# This is (approximately) how it's actually written
def choice(iterable):
#choose from iterable
is cleaner than this:
# This is kind of ugly
def choice(*args):
#make sure *args exists, choose from among them.
The way it is actually written allows you to pass it one single iterable item of any kind, which is both clean and convenient. If it was defined the second way, it would be easy to screw up when using it: someone could call random.choice([1, 2, 3]) and they would always get back [1, 2, 3]!