For loop iterating through the list - python

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

Related

double list in return statement. need explanation in python

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)

Finding every possible list made by removing the first element from either of two lists and appending to the new list

I have two lists of ints, a and b, which do not necessarily have the same length. I would like to create new lists from these by removing either the first element of a, or the first element of b, and appending it to the new list, repeating this step until both a and b are empty. At each step in this process, the number of possible lists grows exponentially, and I'd like to know how to generate every list that is possible to create in this way.
So far, I've only managed to work out that the number of possible lists is equal to sum((2**i for i in range(len(a) + len(b)))). I have no idea how to proceed with this, and would appreciate any pointers.
For information, my end goal is to work out the sum of the differences between consecutive elements for each list, and find the minimum of these.
I think this can be achieved by using recursion. Some code.
permutation = [0]*10 # size of this list has to be equal to lenth of list1 + length of list2. (you can have 4 as the size of the list).
def task(list1,list2,index):
if len(list1)==0 and len(list2)==0: # if length of both the list is 0, we print the
print(permutation) # permutation list
return
if len(list1)>0:
permutation[index] = list1[0]
modified_list1 = list1[:] # Since lists in python are passed by reference, I am making a copy of the list
modified_list1.pop(0) # Removing the first element
task(modified_list1,list2,index+1) #and calling the function again using the modified list.
if len(list2)>0:
permutation[index] = list2[0]
modified_list2 = list2[:]
modified_list2.pop(0)
task(list1,modified_list2,index+1)
if __name__=="__main__":
list1 = [1]
list2 = [4,5,6]
task(list1,list2,0)
Recursive solutions can be a little tricky to understand, I will encourage you
to take a copy and pen and try simulating it for small input, you will
understand how things are working.
For your next task, when we are printing the permutation list, you can compute the differences of the adjacent numbers and store your result in any way you want.

Using comprehensions instead of a for loop

The following is a simplified example of my code.
>>> def action(num):
print "Number is", num
>>> items = [1, 3, 6]
>>> for i in [j for j in items if j > 4]:
action(i)
Number is 6
My question is the following: is it bad practice (for reasons such as code clarity) to simply replace the for loop with a comprehension which will still call the action function? That is:
>>> (action(j) for j in items if j > 2)
Number is 6
This shouldn't use a generator or comprehension at all.
def action(num):
print "Number is", num
items = [1, 3, 6]
for j in items:
if j > 4:
action(i)
Generators evaluate lazily. The expression (action(j) for j in items if j > 2) will merely return a generator expression to the caller. Nothing will happen in it unless you explicitly exhaust it. List comprehensions evaluate eagerly, but, in this particular case, you are left with a list with no purpose. Just use a regular loop.
This is bad practice. Firstly, your code fragment does not produce the desired output. You would instead get something like: <generator object <genexpr> at 0x03D826F0>.
Secondly, a list comprehension is for creating sequences, and generators a for creating streams of objects. Typically, they do not have side effects. Your action function is a prime example of a side effect -- it prints its input and returns nothing. Rather, a generator should for each item it generates, take an input and compute some output. eg.
doubled_odds = [x*2 for x in range(10) if x % 2 != 0]
By using a generator you are obfuscating the purpose of your code, which is to mutate global state (printing something), and not to create a stream of objects.
Whereas, just using a for loop makes the code slightly longer (basically just more whitespace), but immediately you can see that the purpose is to apply function to a selection of items (as opposed to creating a new stream/list of items).
for i in items:
if i < 4:
action(i)
Remember that generators are still looping constructs and that the underlying bytecode is more or less the same (if anything, generators are marginally less efficient), and you lose clarity. Generators and list comprehensions are great, but this is not the right situation for them.
While I personally favour Tigerhawk's solution, there might be a middle ground between his and willywonkadailyblah's solution (now deleted).
One of willywonkadailyblah's points was:
Why create a new list instead of just using the old one? You already have the condition to filter out the correct elements, so why put them away in memory and come back for them?
One way to avoid this problem is to use lazy evaluation of the filtering i.e. have the filtering done only when iterating using the for loop by making the filtering part of a generator expression rather than a list comprehension:
for i in (j for j in items if j > 4):
action(i)
Output
Number is 6
In all honesty, I think Tigerhawk's solution is the best for this, though. This is just one possible alternative.
The reason that I proposed this is that it reminds me a lot of LINQ queries in C#, where you define a lazy way to extract, filter and project elements from a sequence in one statement (the LINQ expression) and can then use a separate for each loop with that query to perform some action on each element.

Compare each list's element with others in the list

So, there is a list like
list=["one","two","ne","three"....]
I wonder, how do I compare each element of the list with others by using endswith() method?
in this list, for example, list[0] endwith list[2].
I couldn't get how to make a comparison itself.
I'm trying something like:
aa=list
flg=False
for i in range(len(ll)-1):
aa.append(ll[i+1])
if ll[i].endswith(aa[i]):
flg=True
however, it's good only for the first element, not with each one.
Using sets:
words = {"one","two","ne","three"}
[x for x in words if any(word.endswith(x) for word in words - {x})]
Out[69]: ['ne']
Basically, for each element, remove it from the words set, and then test if any of the other words in the truncated set end with that word.
You are only doing a single pass through the list, even though you have stated your goal as "Compare each element of the list with the others". This necessitates making one traversal of the list per element in the list. If you have n items, you will traverse the list n times for every item, for a total of n^2 traversals.
Hence, you need two for loops in your solution: one to traverse the list once and select the element that will be compared, and inside that loop, another that will check that element against the others.
for n in ll:
for m in ll:
if m.endswith(n) and m != n:
print(m, "ends with", n)

Python for loop?

I am having trouble understanding a Python for loop. For example, here is some code I've made while I'm learning:
board = []
for i in range (0,5):
board.append(["O"] * 5)
Don't worry about what the code does, I just don't understand what the "i" variable means.
Think of it as substitution.
range(0,5) is [0,1,2,3,4]. The for-loop goes through each element in the list, naming the element i.
for i in range(0,5):
# Starts with 0
print i # prints 0
# now goes back, goes through next element in list: 1.
Prints 0,1,2,3,4.
In your example, i is a placeholder. It is used simply just to loop something x amount of times (in this case, five as the length of range(0,5) is 5)
Also, have fun learning python at Codecademy (I recognise the task :p)
It's an iterator, you can see it as a bucket that stores the result of each iteration; the thing that adds confusion is the fact that it's simply unused in your script, this is another script with a "more involved" use of iterators.
fruits = ['banana', 'apple', 'strawberry', 'coconut', 'cherry']
for yup in fruits:
print(yup)
as you can see you can name it as you want, it's the syntax that makes that word an iterator.
It's an unused variable. Python syntax requires a variable in that position, but you don't do anything with it since you simply want to repeat an action 5 times.
Some people prefer the convention of naming an unused variable like this _:
for _ in range(5)
but this name can interfere with gettext.
In short, i refers to the current element in the list.
Your list is defined as: 0, 1, 2, 3, 4 and 5. Therefore i will iterate this list and assign itself to the next item, i is 0, next iteration i will be 1, next iteration i will be 2 etc.
Directly from python.org:
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)
words = ['cat', 'window', 'defenestrate']
for w in words:
print w, len(w)
Results in:
cat 3
window 6
defenestrate 12
http://docs.python.org/2/tutorial/controlflow.html
The for loop iterates over the given list of objects which is [0, 1, 2, 3, 4] obtained from range(0,5) and in every iteration, you need a variable to get the iterated value. That is the use i here. You can replace it with any variable to get the value.
for n in range(0, 5):
print n #prints 0, then 1, then 2, then 3,then 4 in each iteration
Another example:
for n in ('a', 'b', 'c'):
print n #prints a, then b, then c in each iteration
But in the code you have given, the variable i is not used. It is being used. just to iterate over the list of objects.
In c/java the for loop wiil be:
for(int i=0;i<=10;i++)
{
//for-loop-body
}
here for every iteration i will be incrementing +1 value till i reaches 10, after that it comes out of loop.
In same way,in python the for loop looks like:
for i in range(0,10):
//for-loop-body
here i performs same operation and i is just a variable to increment a value.

Categories

Resources