I'm curious as to why the comma can be added at the end of len(list) to refer to the last item in the list. Can anyone explain this?
Does it work only in list? How about the other items in the list - Can I access by using len(list) as well?
list=[10,20,30,40,50,60]
for num in len(list),:
print(num,end=" ")
Output num is 6.
len(list) returns a single integer, corresponding to the number of elements in your list list (which, as an aside, is poorly named as you should avoid using built-in names for your variables). The comma in for num in len(list), turns it into a one-tuple, meaning that the for loop can iterate one item, which you can see by running in the interactive interpreter:
len(list),
Output:
(6,)
Your for loop, as you indicate, will print: 6, which is the length of list. It does not access the last element of list, which is 60.
This for loop is unusual usage of this syntax, as it's obvious that there will only be a single element and no need to iterate.
for num in len(nums),:
Is the equivalent of:
>>> nums = [10,20,30,40,50,60]
>>> for num in (len(nums), ):
... print(num)
...
6
Where (len(nums), ) is a one-tuple, a tuple with 1 single element.
The reason for this notation is because if I do
(len(nums)) without the ending , (comma) then Python decides that is just the same as len(nums) and not a tuple at all, since we need the ability to use brackets for many things eg. for operations like
(1 + 2) * 3
So we have the ending comma to distinguish a tuple
With lists this is not necessary and we can simply write something like [len(nums)]
Related
So I was trying to complete this kata on code wars and I ran across an interesting solution. The kata states:
"Given an array of integers, find the one that appears an odd number of times.
There will always be only one integer that appears an odd number of times."
and one of the solutions for it was:
def find_it(seq):
return [x for x in seq if seq.count(x) % 2][0]
My question is why is there [0] at the end of the statement. I tried playing around with it and putting [1] instead and when testing, it passed some tests but not others with no obvious pattern.
Any explanation will be greatly appreciated.
The first brackets are a list comprehension, the second is indexing the resulting list. It's equivalent to:
def find_it(seq):
thelist = [x for x in seq if seq.count(x) % 2]
return thelist[0]
The code is actually pretty inefficient, because it builds the whole list just to get the first value that passed the test. It could be implemented much more efficiently with next + a generator expression (like a listcomp, but lazy, with the values produced exactly once, and only on demand):
def find_it(seq):
return next(x for x in seq if seq.count(x) % 2)
which would behave the same, with the only difference being that the exception raised if no values passed the test would be IndexError in the original code, and StopIteration in the new code, and it would operate more efficiently by stopping the search the instant a value passed the test.
Really, you should just give up on using the .count method and count all the elements in a single pass, which is truly O(n) (count solutions can't be, because count itself is O(n) and must be called a number of times roughly proportionate to the input size; even if you dedupe it, in the worst case scenario all elements appear twice and you have to call count n / 2 times):
from collections import Counter
def find_it(it):
# Counter(it) counts all items of any iterable, not just sequence,
# in a single pass, and since 3.6, it's insertion order preserving,
# so you can just iterate the items of the result and find the first
# hit cheaply
return next(x for x, cnt in Counter(it).items() if cnt % 2)
That list comprehension yields a sequence of values that occur an odd number of times. The first value of that sequence will occur an odd number of times. Therefore, getting the first value of that sequence (via [0]) gets you a value that occurs an odd number of times.
Happy coding!
That code [x for x in seq if seq.count(x) % 2] return the list which has 1 value appears in input list an odd numbers of times.
So, to make the output as number, not as list, he indicates 0th index, so it returns 0th index of list with one value.
There is a nice another answer here by ShadowRanger, so I won't duplicate it providing partially only another phrasing of the same.
The expression [some_content][0] is not a double list. It is a way to get elements out of the list by using indexing. So the second "list" is a syntax for choosing an element of a list by its index (i.e. the position number in the list which begins in Python with zero and not as sometimes intuitively expected with one. So [0] addresses the first element in the list to the left of [0].
['this', 'is', 'a', 'list'][0] <-- this an index of 'this' in the list
print( ['this', 'is', 'a', 'list'][0] )
will print
this
to the stdout.
The intention of the function you are showing in your question is to return a single value and not a list.
So to get the single value out of the list which is built by the list comprehension the index [0] is used. The index guarantees that the return value result is taken out of the list [result] using [result][0] as
[result][0] == result.
The same function could be also written using a loop as follows:
def find_it(seq):
for x in seq:
if seq.count(x) % 2 != 0:
return x
but using a list comprehension instead of a loop makes it in Python mostly more effective considering speed. That is the reason why it sometimes makes sense to use a list comprehension and then unpack the found value(s) out of the list. It will be in most cases faster than an equivalent loop, but ... not in this special case where it will slow things down as mentioned already by ShadowRanger.
It seems that your tested sequences not always have only one single value which occurs an odd number of times. This will explain why you experience that sometimes the index [1] works where it shouldn't because it was stated that the tested seq will contain one and only one such value.
What you experienced looking at the function in your question is a failed attempt to make it more effective by using a list comprehension instead of a loop. The actual improvement can be achieved but by using a generator expression and another way of counting as shown in the answer by ShadowRanger:
from collections import Counter
def find_it(it):
return next(x for x, cnt in Counter(it).items() if cnt % 2)
list=(1,2,3,4)
for x in range(len(list)):
print(list[x])
1
2
3
4
but print(list) repeats the whole list 4 times, i.e.
1,2,3,4
1,2,3,4
1,2,3,4
How does the x in the print(list[x]) cause only single numbers to come out? Like how could you put what the [x] is doing in English?
The 'x' represents a number, which changes with each iteration of the for loop. When you do list[x], you are getting the xth number in list, starting at 0.
x represents the index within the list. Using list[x] is actually picking the element in the x position from the list.
For each time through the loop x takes on values 0, 1, 2, etc. list[x] is then list[0], list[1], where the square brackets extract a single list element.
Note: for good python form consider using a different variable name (such as lst) to avoid confusion with builtin python names.
You are telling the program that in range of list's length (4), run the following command:
print(list)
So it will print all the list items 4 times.
"Like how could you put what the [x] is doing in English?"
for item in list:
print(item)
And as other friends said, don't use "list" for variable name.
Question
I want to remove items from a list such that I keep the first n items, and remove the next 2n items.
For example
for n=8, I want to keep the first 8, remove the next 16 and repeat this as necessary:
a = range(48)
Which I want to become
[0,1,2,3,4,5,6,7,24,25,26,27,28,29,30,31]
This is to pick out the first 8 hours of a day, and run a function on each hour.
I've found it hard to phrase this in search queries so the answer is probably simple but I've had no luck!
You could just use a comprehension list:
[ a[i] for i in range(len(a)) if (i % 24 < 8) ]
The above only create a new list. If you want to edit the list in place, you must explicitely delete unwanted elements, starting from the end to avoid changing indexes:
for i in range(len(a) - 1, 0, -1):
if i % 24 >= 8:
del a[i]
def hours(n):
items = [x for x in range(49)]
del items[n:n*3]
print(items)
hours(8)
Depending on how new you are you might have a hard time understanding this code, so I will try to explain a little:
We start by creating a function which takes a parameter n which, for test purposes, we will be using 8 then we use a list comprehension to generate all our numbers (0, 48) and then delete the unneeded elements using the del statement, we are deleting from the nth to the n*3 element in the list. For example, if n were to be passed as 9 our use of the del statement could be translated as: del [9:27].
Hope this makes sense.
This should be quite easy to understand
a = range(48)
n=8
result=[]
while a:
result+= a[:n]
a=a[n*3:]
print result
I am learning the python from the Codeacademy website and I came across the loops section which is a little vague and hard to me. When the website wants to explain how does a for loop works, it gets help from lists. Like so:
for i in list34:
#Some codes
The website says that when you run a for loop statement for a list, the for loop would iterate through the elements of the list then save them in i variable.
I just don't get the iterating through concept!
What does it mean?
Maybe some code example will help!
>>> li = [4,3,1,2,0]
>>> for x in li:
... print(x)
...
4
3
1
2
0
>>>
What the for loop does is, it takes one item in the list at a time and assigns that item to the variable x. As the for loop takes items of lists one by one, it is called iterating through/on the list.
for i in list34:
#Some codes
This snippet will go through all the items of list34 (i.e., iterate through them).
In each iteration ("step" of the loop), i will be assigned the next value from the list, so your code could do something with it (e.g., print it out).
iterating over a list, or any data structure for that matter, means that it just takes every element, one after the other, from the given structure an does something with it.
in this case you have your i elements and you do stuff with them inside the for loop. the for statement makes sure, that every element of the list is handled.
The for statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python’s for statement iterates over the items of any sequence (a list or a string), in the order that they appear in the sequence. For example (no pun intended):
# Measure some strings:
words = ['cat', 'window', 'defenestrate']
for w in words:
print w, len(w)
If you need to modify the sequence you are iterating over while inside the loop (for example to duplicate selected items), it is recommended that you first make a copy. Iterating over a sequence does not implicitly make a copy. The slice notation makes this especially convenient:
for w in words[:]: # Loop over a slice copy of the entire list.
if len(w) > 6:
words.insert(0, w)
words
If you do need to iterate over a sequence of numbers, the built-in function range() comes in handy. It generates lists containing arithmetic progressions:
range(10)
The given end point is never part of the generated list; range(10) generates a list of 10 values, the legal indices for items of a sequence of length 10. It is possible to let the range start at another number, or to specify a different increment (even negative; sometimes this is called the ‘step’):
range(5, 10)
range(0, 10, 3)
range(-10, -100, -30)
To iterate over the indices of a sequence, you can combine range() and len() as follows:
a = ['Mary', 'had', 'a', 'little', 'lamb']
for i in range(len(a)):
print i, a[i]
Read More: docs.python.org
I am stuck in making a loop that will eliminate the values(from the alist) that are below average.
Thanks for the help.
a=input("Enter a list of values separated by a coma : ")
alist=eval(a)
print("the list is : ",alist)
average = sum(alist)/len(alist)
print("the average is : ",average)
for i in alist:
if alist[i]<average:
alist.remove[i]
You are almost there. Instead of removing elements, select elements you want to retain instead:
alist = [a for a in alist if a>=average]
Your mistake here is that for i in alist: is iterating over list elements themselves, not indexes, so alist[i] is throwing an error (or returning nonsense).
For the "loop" you can use a filter and a lambda function.
above_average = list(filter(lambda x: x >= average, alist))
For the rest of your code, I suggest you clean it up to something which is safer (use of eval is very bad)
import ast
user_string = raw_input('input a list of numbers separated by a commas: ')
alist = list(ast.literal_eval(user_string)))
So, in all, I would write your code as something like this:
import ast
user_string = raw_input('input a list of numbers separated by a commas: ')
numbers = list(ast.literal_eval(user_string)))
average = sum(numbers)/len(numbers)
print('The numbers: {}'.format(numbers))
print('The average: {}'.format(average))
above_average = list(filter(lambda x: x >= average, numbers))
# now do what you want with the above_average numbers.
Other answers tell you how to do it. I'll tell you why it doesn't work:
You iterate over the list and, at the same time, modify it.
This leads to items being missed during the iteration.
Why?
Internally, the iteration works via an index to the list. So it is the same as doing
idx = 0
while True:
try:
i = alist[idx]
except IndexError:
break
idx += 1
if alist[i] < average:
alist.remove(i)
What happens if you are at the element #3, go to the next one and then remove #3? Right, the indexes of the remaining ones move down and you are pointing to the one which formerly was #5. The old #4 is skipped at this test.
(BTW, I don't know if you noticed, I have replaced your [] behind .remove with ().)
You are mixing two ways of iterating a list: By index, and by element. In your loop, i is not the index, but the element of the list itself, thus alist[i] won't work.
If you use the for x in somelist loop, then x is the element itself, not the index of the element. For iterating over the indices, you can use for i in range(len(somelist)), or you could use for i, x in enumerate(somelist) to loop over tuples of index and element.
Also note that removing elements from a list or other kinds of collections while you are looping them generally is a bad idea. Better create a copy of the list.
for x in list(alist): # creates a copy of alist
if x < average: # remember: x is the element itselt
alist.remove(x) # remove element x from list
But the way you do it (with eval of a comma-separated string of numbers), alist is a tuple, not a list, and thus has no remove method at all. Thus you either have to convert it to a list before (alist = list(eval(a)), or use one of the approaches given in the other answers, creating a new list using list comprehension or filter and retaining the "good" elements.
As a general principle for asking StackOverflow questions like this, you should always include example input and output -- show what happens, and what you expect to happen.
In this case, I believe there are two three problems with your code:
Edit: Third, but possibly most importantly, look at glglgl's answer. If you implement the two fixes I describe below, you'll still have one problem: your code won't necessarily remove all the items you want to remove, because it'll skip over some items.
First, you say alist[i], which grabs the element of alist at index i. But saying for i in alist makes i be successive elements in the list already. Example:
mylist = [1, 2, 4]
for i in mylist:
print(i)
Would give you the output:
1
2
4
If you instead said this (which is like what you wrote)
mylist = [1, 2, 4]
for i in mylist:
print(mylist[i])
It wouldn't work as you'd expect, because you'd get the element at index 1, the element at index 2, and then try to get the element at index 4, but that wouldn't exist. You'll get something like this:
2
4
IndexError: list index out of range
Second, your syntax for removing an element is wrong. You should use alist.remove(i) instead of alist.remove[i]. You want to call a function, so you use parentheses. The square brackets are for indexing and slicing.