Can anyone explain how x is taking integer values. We are directly using x in for loop "for x in a"
How is the compiler going to recognize it that x represents the strings inside the list?
>>> # Measure some strings:
... a = ['cat', 'window', 'defenestrate']
>>> for x in a:
... print x, len(x)
...
cat 3
window 6
defenestrate 12
for works differently in Python than it works in languages like C. Instead of counting up/down a numerical value and checking an end condition as you usually would in C:
for (i=0; i<=max; i++) do_something();
it iterates over all the elements in the container (whose name is referenced after the in):
for item in iterable:
do_something(item)
Its precise behavior depends on the type of container (iterable) used; in a list or tuple, it will start at the first element, then move through the list/tuple one item at a time until the final element has been reached. Each of the elements will be then referenced by a name (item in this example) so that it can be operated on in the body of the loop.
In a dictionary, for would iterate through the dictionary's keys (in an unspecified order), so item would contain a key of the dictionary.
In a string, it iterates through the letters of the string, one by one. Etc.
how X is taking integer values
It's not. It is taking the successive values contained in the sequence you're iterating over, which is this case are strings.
The elements don't have to be of a particular type, nor do they even have to be of the same type.
To be a little bit more technical, the for loop iterates over an iterator provided by an iterable.
An iterable can be a list, a string, a tuple etc., an iterator is an object used for iteration.
With for i in a:, you request for an iterator for a, exactly the way you do with iter(a).
This happens
either by calling the_iterator = a.__iter__()
or, if that doesn't work, but a has a __getitem__(), by calling this with successively growing indexes until IndexError is raised.
This interator is then called .next() (.__next__() in Python 3) on each loop run until the iterator is exhausted and raises StopIteration.
So, in other words:
for x in a: print x, len(x)
internally works like
a_iter = iter(a)
while True:
try: x = next(a)
except StopIteration: break
print x, len(x)
but looks much nicer.
Related
RTX_number = [int(x) for x in input().split()]
Could someone explain this line of code to me step by step?
I am having great difficulty understanding it.
As far as I know, .split creates spaces between elements?
I saw this code on a forum and I am trying to get a better understanding of it because I think it might be helpful for a simulation project.
I heard this is called a list comprehension, but I am kind of lost as of for now.
input().split()
Reads a line and breaks it where ever there is a space into a list of strings.
for x in input().split()
Takes this list, runs over it item by item, and binds this item to x.
int(x) for ...
Takes this x we bound, and runs int(x) on it and returns it.
[int(x) for x in input().split()]
Takes all these results and puts them into a list.
The short version is that this:
RTX_number = [int(x) for x in input().split()]
is a short-form of this:
RTX_number = []
for x in input().split():
RTX_number.append(int(x))
where input().split() returns the list of strings that you get from separating whatever input() returned on each whitespace (for example, "Hello World" becomes ["Hello", "World"].
The str.split() function can also be given an argument, such as ',', which it will split on instead of whitespace.
The general syntax of a comprehension is
(expression) for (element) in (iterable) if (condition)
For every element element in the iterable, if the condition resolves to True (note that the condition can be omitted entirely) the expression is evaluated and added to the returned list.
We usually use comprehensions as shorthand for full loops, since they often save space and complexity.
Note that list comprehensions aren't the only kind of comprehension - they can be used to make several different data structures:
# list comprehension - produces a list
[expression for element in iterable]
# set comprehension - produces a set instead of a list
{expression for element in iterable}
# dict comprehension - produces a dict with key-value pairs
{key:value for element in iterable}
# generator comprehension - like a list comprehension, but each expression is not
# actually evaluated until something tries to read it.
# The parentheses are technically optional, if the syntax isn't ambiguous
(expression for element in iterable)
This code is equivalent to:
# ask user input (it expected something like "1 2 34 5")
input_text = input()
# split on spaces
split_text_list = input_text.split()
list_of_integers = []
# for each string item in list
for item in split_text_list:
# convert to integer
number = int(item)
# add to list
list_of_integers.append(number)
But of course it avoids having all the unnecessary intermediate variables, so it is shorter. Also faster as it doesn't require to store the intermediate values.
Really sorry for my bad English first,
I made two functions to continually modify (actually remove one by one) the elements in the list and to show the last element in the end, but the removing function is not giving impact on the list that I want to modify.
I think this is a problem about local-variables and mutability of list, but I don't know how to fix it.
At first, I give a list as an argument of one of the functions that I made, removing function. Removing function removes the element until it has only one element USING THE OTHER FUNCTION. In that function, I put my other function(I'll call this checking function) in. Checking function checks the elements to remove, and 'actually' remove one element in my code, but returns nothing.
Please note x and y variable is random value in range of length of seq (I did not write this in my example code),
and they will be changed every time in while loop in removing function.
import random
def checking(x, y, seq):
positions = [x, y]
positions.sort()
if seq[x] == 'b' and seq[y] == 'b':
seq.pop(positions[1])
seq.pop(positions[0])
seq.append('a')
else:
seq.pop(positions[1])
seq.pop(positions[0])
seq.append('b')
def removing(seq):
while len(seq) != 1:
x, y = random1, random2
remove(x, y, list(seq))
return seq[0]
final(['a','a','b','a','b'])
I tested checking function is working well thus, I think this is problem of removing function.
I expected the list seq modified every time passing 'remove' function and finally return the last element, but there's nothing changed and stuck in infinite loop.
Thank you for reading my question.
list(seq) makes a new list instance where its items are shallow copies of seq items.
The while loop never terminates for this reason as the list never empties.
Pass the same seq to remove function instead of making a new list instance.
remove(x, y, seq)
When given argument is a tuple, convert it to a mutable list before going into the loop:
seqm = list(seq)
while len(seqm) != 1:
x, y = random1, random2
remove(x, y, seqm)
return seqm[0]
Is a loop of the form
for x in range(3):
print x
guaranteed to output
0
1
2
in that order? In other words, if you loop over a list with a for item in mylist statement, is the loop guaranteed to start at mylist[0] and proceed sequentially (mylist[1], mylist[2], ...)?
Yes, the builtin list and range will always iterate in the order you expect. Classes define their own iteration sequence, so the iteration order will vary between different classes. Due to their nature set and dict (amongst others) won't iterate in a predictable order.
You can define any iteration sequence you want for a class. For example, you can make a list that will iterate in reverse.
class reversedlist(list):
def __iter__(self):
self.current = len(self)
return self
def next(self):
if self.current <= 0:
raise StopIteration
self.current -= 1
return self[self.current]
x = reversedlist([0, 1, 2, 3, 4, 5])
for i in x:
print i,
# Outputs 5 4 3 2 1 0
Yes it does. It is not the for loop that guarantees anything, but the range function though. range(3) gives you an iterator that returns 0, then 1 and then 2. Iterators can only be accessed one element at a time, so that is the only order the for loop can access the elements.
Other iterators (ones not generated by the range function for example) could return elements in other orders.
is the loop guaranteed to start at mylist[0] and proceed sequentially (mylist[1], mylist[2], ...)?
When you use a for loop, the list gets used as an iterator. That is, the for loop actually does not index into it. It just keeps calling the next function until there are no more elements. In this way the for loop itself has no say in what order elements gets processed.
Yes, it is.
A python for loop like this:
for e in list:
print e
can be traslated as:
iterator = list.__iter__()
while True:
try:
e = iterator.next()
except StopIteration:
break
print e
So, while the "next" method of the object iterator returns values in the "correct" order you will get the elements in the "correct" order.
For python list this is guaranteed to happen.
For more information look here and here
Yes. for loops in Python traverse a list or an iter in order. range returns a list in Python 2.x and an iterator in Python 3.x, so your for x in range(3) loop will indeed always be ordered.
However, the same cannot be said for dicts or sets. They will not be traversed in order - this is because the order of their keys is undefined.
Yes, it starts with the first element of a list and goes to the last.
Not all data types in python do that, such as dicts, but lists certainly do. range(x) certainly will.
Yes.
But with a dictionary thereĀ“s no order guaranteed.
Yes. Python docs about For Loop say:
Basically, any object with an iterable method can be used in a for loop in Python ... Having an iterable method basically means that the data can be presented in list form, where there's multiple values in an orderly fashion
How can I update the upper limit of a loop in each iteration? In the following code, List is shortened in each loop. However, the lenList in the for, in loop is not, even though I defined lenList as global. Any ideas how to solve this? (I'm using Python 2.sthg)
Thanks!
def similarity(List):
import difflib
lenList = len(List)
for i in range(1,lenList):
import numpy as np
global lenList
a = List[i]
idx = [difflib.SequenceMatcher(None, a, x).ratio() for x in List]
z = idx > .9
del List[z]
lenList = len(List)
X = ['jim','jimmy','luke','john','jake','matt','steve','tj','pat','chad','don']
similarity(X)
Looping over indices is bad practice in python. You may be able to accomplish what you want like this though (edited for comments):
def similarity(alist):
position = 0
while position < len(alist):
item = alist[position]
position += 1
# code here that modifies alist
A list will evaluate True if it has any entries, or False when it is empty. In this way you can consume a list that may grow during the manipulation of its items.
Additionally, if you absolutely have to have indices, you can get those as well:
for idx, item in enumerate(alist):
# code here, where items are actual list entries, and
# idx is the 0-based index of the item in the list.
In ... 3.x (I believe) you can even pass an optional parameter to enumerate to control the starting value of idx.
The issue here is that range() is only evaluated once at the start of the loop and produces a range generator (or list in 2.x) at that time. You can't then change the range. Not to mention that numbers and immutable, so you are assigning a new value to lenList, but that wouldn't affect any uses of it.
The best solution is to change the way your algorithm works not to rely on this behaviour.
The range is an object which is constructed before the first iteration of your loop, so you are iterating over the values in that object. You would instead need to use a while loop, although as Lattyware and g.d.d.c point out, it would not be very Pythonic.
What you are effectively looping on in the above code is a list which got generated in the first iteration itself.
You could have as well written the above as
li = range(1,lenList)
for i in li:
... your code ...
Changing lenList after li has been created has no effect on li
This problem will become quite a lot easier with one small modification to how your function works: instead of removing similar items from the existing list, create and return a new one with those items omitted.
For the specific case of just removing similarities to the first item, this simplifies down quite a bit, and removes the need to involve Numpy's fancy indexing (which you weren't actually using anyway, because of a missing call to np.array):
import difflib
def similarity(lst):
a = lst[0]
return [a] + \
[x for x in lst[1:] if difflib.SequenceMatcher(None, a, x).ratio() > .9]
From this basis, repeating it for every item in the list can be done recursively - you need to pass the list comprehension at the end back into similarity, and deal with receiving an empty list:
def similarity(lst):
if not lst:
return []
a = lst[0]
return [a] + similarity(
[x for x in lst[1:] if difflib.SequenceMatcher(None, a, x).ratio() > .9])
Also note that importing inside a function, and naming a variable list (shadowing the built-in list) are both practices worth avoiding, since they can make your code harder to follow.
Python's list type has an index(x) method. It takes a single parameter x, and returns the (integer) index of the first item in the list that has the value x.
Basically, I need to invert the index(x) method. I need to get the index of the first value in a list that does NOT have the value x. I would probably be able to even just use a function that returns the index of the first item with a value != None.
I can think of a 'for' loop implementation with an incrementing counter variable, but I feel like I'm missing something. Is there an existing method, or a one-line Python construction that can handle this?
In my program, the situation comes up when I'm handling lists returned from complex regex matches. All but one item in each list have a value of None. If I just needed the matched string, I could use a list comprehension like '[x for x in [my_list] if x is not None]', but I need the index in order to figure out which capture group in my regex actually caused the match.
Exiting at the first match is really easy: instead of computing a full list comprehension (then tossing away everything except the first item), use next over a genexp. Assuming for example that you want -1 when no item satisfies the condition of being != x,
return next((i for i, v in enumerate(L) if v != x), -1)
This is Python 2.6 syntax; if you're stuck with 2.5 or earlier, .next() is a method of the genexp (or other iterator) and doesn't accept a default value like the -1 above (so if you don't want to see a StopIteration exception you'll have to use a try/except). But then, there is a reason more releases were made after 2.5 -- continuous improvement of the language and its built-ins!-)
Using a list comprehension when you only need the first just feels slimy (to me). Use a for-loop and exit early.
>>> lst = [None, None, None, "foo", None]
>>> for i, item in enumerate(lst):
... if item: break
... else:
... print "not found"
...
>>> i
3
enumerate() returns an iterator that yields a tuple of the current index of the iterable as well as the item itself.
[i for i, x in enumerate(my_list) if x != value][0]
If you're not sure whether there's a non-matching item, use this instead:
match = [i for i, x in enumerate(my_list) if x != value]
if match:
i = match[0]
# i is your number.
You can make this even more "functional" with itertools, but you will soon reach the point where a simple for loop is better. Even the above solutions aren't as efficient as a for loop, since they construct a list of all non-matching indices before you pull the one of interest.
A silly itertools-based solution:)
import itertools as it, operator as op, functools as ft
def index_ne(item, sequence):
sequence= iter(sequence)
counter= it.count(-1) # start counting at -1
pairs= it.izip(sequence, counter) # pair them
get_1st= it.imap(op.itemgetter(0), pairs) # drop the used counter value
ne_scanner= it.ifilter(ft.partial(op.ne, item), get_1st) # get only not-equals
try:
ne_scanner.next() # this should be the first not equal
except StopIteration:
return None # or raise some exception, all items equal to item
else:
return counter.next() # should be the index of the not-equal item
if __name__ == "__main__":
import random
test_data= [0]*20
print "failure", index_ne(0, test_data)
index= random.randrange(len(test_data))
test_data[index]= 1
print "success:", index_ne(0, test_data), "should be", index
All this just to take advantage of the itertools.count counting :)