Process at least one line in Python - python

I have the following code structure in my Python script:
for fullName in lines[:-1]:
do stuff ...
This processes every line except for the last one. The last line is a company name and all the rest are people's names. This works except in the case where there's no company name. In this case the loop doesn't get executed. There can only be one name if there's no company name. Is there a way to tell Python to execute this loop at least once?

You could do it like this, dynamically setting the end of your range based on the length of lines:
i = len(lines)
i = -1 if i > 1 else i
for fullName in lines[:i]:
dostuff()

How about using Python's conditional:
>>> name=['Roger']
>>> names=['Pete','Bob','Acme Corp']
>>>
>>> tgt=name
>>> for n in tgt if len(tgt)==1 else tgt[:-1]:
... print(n)
...
Roger
>>> tgt=names
>>> for n in tgt if len(tgt)==1 else tgt[:-1]:
... print(n)
...
Pete
Bob

Use an if-statement:
if len(fullName) == 1: # Only one person
dostuff_with_one_person()
else:
for fullName in lines[:-1]:
dostuff()

This is essentially a do-while loop construct in Python.
Essentially, you can have a for loop or while loop with a break condition. For yours, you could do this:
def do_stuff(x):
print(x)
for i,n in enumerate(lst):
do_stuff(n)
if i>=len(lst)-2:
break

Straightforward method. Processing only till the last but one record, if there are more than one records.
for i in xrange(len(lines)):
process lines[i]
if i == len(lines)-2: break
If there is only one element, i will be 0 and that will be processed and i != -1. If There are more than one elements, lets say 2. After processing the first element, i will be 0 and i == (2-2) will be true and breaks out of the loop.

Related

Alternate apporach for using a flag in python

What is the best/alternate pythonic way for the code below,
li=["Header",1,2,3,4,5]
l=0
for i in li:
if l == 0:
.....
l += 1
else:
....
You can replace:
l=0
for i in li:
if l ==0:
frobnosticate(i)
l+= 1
else:
twiddle(i)
With:
#do something with header outside the loop
frobnosticate(li[0])
#loop over everything but the first element
for i in li[1:]:
twiddle(i)
li=["Header",1,2,3,4,5]
do_stuff(li[0]) # first ....
for i in li[1:]:
normal_stuff(i) # second ...
This will deal with header first and then iterate through rest of list.
Accessing such pattern of elements using slicing is good enough. However, if data type in your list is not fixed/known, you may also use dictionary to redirect element to specified function:
def access_string_element(string):
....
def access_integer_element(integer):
....
access_table = dict()
access_table[str] = access_string_element
access_table[int] = access_integer_element
...
Then you could use the dict like this:
for element in li:
access_table[type(element)](element)
This way benefits if you are going to handle list containing data with different data type. It would make your loop looks clearer, and easy to manage.
Have Fun ;)

Are infinite for loops possible in Python? [duplicate]

This question already has answers here:
Looping from 1 to infinity in Python
(8 answers)
Closed 5 months ago.
The community reviewed whether to reopen this question 4 months ago and left it closed:
Original close reason(s) were not resolved
Is it possible to get an infinite loop in for loop?
My guess is that there can be an infinite for loop in Python. I'd like to know this for future references.
You can use the second argument of iter(), to call a function repeatedly until its return value matches that argument. This would loop forever as 1 will never be equal to 0 (which is the return value of int()):
for _ in iter(int, 1):
pass
If you wanted an infinite loop using numbers that are incrementing you could use itertools.count:
from itertools import count
for i in count(0):
....
The quintessential example of an infinite loop in Python is:
while True:
pass
To apply this to a for loop, use a generator (simplest form):
def infinity():
while True:
yield
This can be used as follows:
for _ in infinity():
pass
Yes, use a generator that always yields another number:
Here is an example
def zero_to_infinity():
i = 0
while True:
yield i
i += 1
for x in zero_to_infinity():
print(x)
It is also possible to achieve this by mutating the list you're iterating on, for example:
l = [1]
for x in l:
l.append(x + 1)
print(x)
In Python 3, range() can go much higher, though not to infinity:
import sys
for i in range(sys.maxsize**10): # you could go even higher if you really want but not infinity
pass
Here's another solution using the itertools module:
import itertools
for _ in itertools.repeat([]): # return an infinite iterator
pass
It's also possible to combine built-in functions iter (see also this answer) and enumerate for an infinite for loop which has a counter:
for i, _ in enumerate(iter(bool, True)):
input(i)
Which prints:
0
1
2
3
4
...
This uses iter to create an infinite iterator and enumerate provides the counting loop variable. You can even set a start value other than 0 with enumerate's start argument:
for i, _ in enumerate(iter(bool, True), start=42):
input(i)
Which prints:
42
43
44
45
46
...
Python infinite for loop
Well, there are a few ways, but the easiest one I found is to Iterate over a list
To understand this you must be knowing about:
python basics
python loops
python lists ( and also its append() function
The syntax is something like this...
l = ['#'] # Creating a list
for i in l: # Iterating over the same list
print(l)
l.append(i) # Appending the same element
With every iteration, the an element gets appended to the list. This way the loop never stops iterating.
Happy coding : )
While there have been many answers with nice examples of how an infinite for loop can be done, none have answered why (it wasn't asked, though, but still...)
A for loop in Python is syntactic sugar for handling the iterator object of an iterable an its methods. For example, this is your typical for loop:
for element in iterable:
foo(element)
And this is what's sorta happening behind the scenes:
iterator = iterable.__iter__()
try:
while True:
element = iterator.next()
foo(element)
except StopIteration:
pass
An iterator object has to have, as it can be seen, anextmethod that returns an element and advances once (if it can, or else it raises a StopIteration exception).
So every iterable object of which iterator'snextmethod does never raise said exception has an infinite for loop. For example:
class InfLoopIter(object):
def __iter__(self):
return self # an iterator object must always have this
def next(self):
return None
class InfLoop(object):
def __iter__(self):
return InfLoopIter()
for i in InfLoop():
print "Hello World!" # infinite loop yay!
we can actually have a for infinite loop
list = []
for i in list:
list.append(i)
print("Your thing")
i found a way without using yield or a while loop.
my python version is python 3.10.1
x = [1]
for _ in x:
x.append(1)
print('Hello World!')
if you need loop count, you can use i+1:
x = [1]
for i in x:
x.append(i+1)
print(f'Hello {i}')
you should know that this is not really an "infinite" loop.
because as the loop runs, the list grows and eventually, you will run out of ram.
Best way in my opinion:
for i in range(int(1e18)):
...
The loop will run for thousands of years
You can configure it to use a list. And append an element to the list everytime you iterate, so that it never ends.
Example:
list=[0]
t=1
for i in list:
list.append(i)
#do your thing.
#Example code.
if t<=0:
break
print(t)
t=t/10
This exact loop given above, won't get to infinity. But you can edit the if statement to get infinite for loop.
I know this may create some memory issues, but this is the best that I could come up with.
n = 0
li = [0]
for i in li:
n += 1
li.append(n)
print(li)
In the above code, we iterate over the list (li).
So in the 1st iteration, i = 0 and the code in for block will run, that is li will have a new item (n+1) at index 1 in this iteration so our list becomes [ 0, 1 ]
Now in 2nd iteration, i = 1 and new item is appended to the li (n+1), so the li becomes [0, 1, 2]
In 3rd iteration, i = 2, n+1 will be appended again to the li, so the li becomes [ 0, 1, 2, 3 ]
This will keep on going as in each iteration the size of list is increasing.
The other solutions solutions have a few issues, such as:
consuming a lot of memory which may
cause memory overflow
consuming a lot of processor power.
creating deadlock.
using 3rd party library
Here is an answer, which will overcome these problems.
from asyncio import run, sleep
async def generator():
while True:
await sleep(2)
yield True
async def fun():
async for _ in generator():
print("Again")
if __name__ == '__main__':
run(fun())
In case you want to do something that will take time, replace sleep with your desired function.
i'm newbie in python but try this
for i in range(2):
# your code here
i = 0
can improve this code
In Python 2.x, you can do:
my_list = range(10)
for i in my_list:
print "hello python!!"
my_list.append(i)

If list index exists, do X

In my program, user inputs number n, and then inputs n number of strings, which get stored in a list.
I need to code such that if a certain list index exists, then run a function.
This is made more complicated by the fact that I have nested if statements about len(my_list).
Here's a simplified version of what I have now, which isn't working:
n = input ("Define number of actors: ")
count = 0
nams = []
while count < n:
count = count + 1
print "Define name for actor ", count, ":"
name = raw_input ()
nams.append(name)
if nams[2]: #I am trying to say 'if nams[2] exists, do something depending on len(nams)
if len(nams) > 3:
do_something
if len(nams) > 4
do_something_else
if nams[3]: #etc.
Could it be more useful for you to use the length of the list len(n) to inform your decision rather than checking n[i] for each possible length?
I need to code such that if a certain list index exists, then run a function.
This is the perfect use for a try block:
ar=[1,2,3]
try:
t=ar[5]
except IndexError:
print('sorry, no 5')
# Note: this only is a valid test in this context
# with absolute (ie, positive) index
# a relative index is only showing you that a value can be returned
# from that relative index from the end of the list...
However, by definition, all items in a Python list between 0 and len(the_list)-1 exist (i.e., there is no need for a try block if you know 0 <= index < len(the_list)).
You can use enumerate if you want the indexes between 0 and the last element:
names=['barney','fred','dino']
for i, name in enumerate(names):
print(i + ' ' + name)
if i in (3,4):
# do your thing with the index 'i' or value 'name' for each item...
If you are looking for some defined 'index' though, I think you are asking the wrong question. Perhaps you should consider using a mapping container (such as a dict) versus a sequence container (such as a list). You could rewrite your code like this:
def do_something(name):
print('some thing 1 done with ' + name)
def do_something_else(name):
print('something 2 done with ' + name)
def default(name):
print('nothing done with ' + name)
something_to_do={
3: do_something,
4: do_something_else
}
n = input ("Define number of actors: ")
count = 0
names = []
for count in range(n):
print("Define name for actor {}:".format(count+1))
name = raw_input ()
names.append(name)
for name in names:
try:
something_to_do[len(name)](name)
except KeyError:
default(name)
Runs like this:
Define number of actors: 3
Define name for actor 1: bob
Define name for actor 2: tony
Define name for actor 3: alice
some thing 1 done with bob
something 2 done with tony
nothing done with alice
You can also use .get method rather than try/except for a shorter version:
>>> something_to_do.get(3, default)('bob')
some thing 1 done with bob
>>> something_to_do.get(22, default)('alice')
nothing done with alice
It can be done simply using the following code:
if index < len(my_list):
print(index, 'exists in the list')
else:
print(index, "doesn't exist in the list")
len(nams) should be equal to n in your code. All indexes 0 <= i < n "exist".
Using the length of the list would be the fastest solution to check if an index exists:
def index_exists(ls, i):
return (0 <= i < len(ls)) or (-len(ls) <= i < 0)
This also tests for negative indices, and most sequence types (Like ranges and strs) that have a length.
If you need to access the item at that index afterwards anyways, it is easier to ask forgiveness than permission, and it is also faster and more Pythonic. Use try: except:.
try:
item = ls[i]
# Do something with item
except IndexError:
# Do something without the item
This would be as opposed to:
if index_exists(ls, i):
item = ls[i]
# Do something with item
else:
# Do something without the item
I need to code such that if a certain list index exists, then run a function.
You already know how to test for this and in fact are already performing such tests in your code.
The valid indices for a list of length n are 0 through n-1 inclusive.
Thus, a list has an index i if and only if the length of the list is at least i + 1.
If you want to iterate the inserted actors data:
for i in range(n):
if len(nams[i]) > 3:
do_something
if len(nams[i]) > 4:
do_something_else
ok, so I think it's actually possible (for the sake of argument):
>>> your_list = [5,6,7]
>>> 2 in zip(*enumerate(your_list))[0]
True
>>> 3 in zip(*enumerate(your_list))[0]
False
You can try something like this
list = ["a", "b", "C", "d", "e", "f", "r"]
for i in range(0, len(list), 2):
print list[i]
if len(list) % 2 == 1 and i == len(list)-1:
break
print list[i+1];
Oneliner:
do_X() if len(your_list) > your_index else do_something_else()
Full example:
In [10]: def do_X():
...: print(1)
...:
In [11]: def do_something_else():
...: print(2)
...:
In [12]: your_index = 2
In [13]: your_list = [1,2,3]
In [14]: do_X() if len(your_list) > your_index else do_something_else()
1
Just for info. Imho, try ... except IndexError is better solution.
Here's a simple, if computationally inefficient way that I felt like solving this problem today:
Just create a list of available indices in my_list with:
indices = [index for index, _val in enumerate(my_list)]
Then you can test before each block of code:
if 1 in indices:
"do something"
if 2 in indices:
"do something more"
but anyone reading this should really just take the correct answer from: #user6039980
Do not let any space in front of your brackets.
Example:
n = input ()
^
Tip:
You should add comments over and/or under your code. Not behind your code.
Have a nice day.

Python iterator question

I have this list:
names = ['john','Jonh','james','James','Jardel']
I want loop over the list and handle consecutive names with a case insensitive match in the same iteration. So in the first iteration I would do something with'john' and 'John' and I want the next iteration to start at 'james'.
I can't think of a way to do this using Python's for loop, any suggestions?
This would be one for itertools.groupby, which groups consecutive equal elements from a list or other iterable. you can specify a function to do the comparison, so that, in your case, the same name in different cases can still be counted as the same thing.
for k, g in itertools.groupby(names, lambda s: s.lower()):
# Example: in the first iteration:
# k = "john"
# g = an iterator over ["john", "John"]
# Process them as you like
names = ['john','John','james','James']
for name, capitalized_name in zip(names[::2], names[1::2]):
print name, capitalized_name
Note that you need an even amount of items for this to work properly.
Or (maybe better; hard to tell with little context) use a set to filter the list to contain only unique names (note that this loses order):
>>> names = ['john','John','james','James','Jardel']
>>> unique_names = set([x.lower() for x in names])
>>> for unique_name in unique_names:
... print unique_name
...
jardel
james
john
You could just use a while loop:
i = 0
while i < len(names):
# compare names[i] with names[i + 1]
i = i + 2 # or + 1 if names not equal, for example
Or are you looking for something a bit more involved?
As you iterate thru the loop, you could try keeping track of the previous name in the list. At the same time, when you're going to store the names, you can make a call to lower() or capitalize() to make the formatting of each name consistent so that you can compare them easier.
e.g.
first = True
prev= ""
for name in names:
if first: #First iteration
prev = name.lower() #Need to get the first elem
do_something_to(curr)
first = False
else:
if prev == name.lower():
print "do nothing"
else:
do_something_to(curr)
prev = name.lower()
May not be the most efficient, but works.
My $0.02:
def byPairs(li):
for i in xrange(1, len(li), 2):
yield (li[i-1], li[i])
for a,b in byPairs(names):
if a.lower()==b.lower():
doSomething(a,b)
I'm not sure I understood the question exactly; what are you trying to accomplish?

any way to loop iteration with same item in python?

It's a common programming task to loop iteration while not receiving next item. For example:
for sLine in oFile :
if ... some logic ... :
sLine = oFile.next()
... some more logic ...
# at this point i want to continue iteration but without
# getting next item from oFile. How can this be done in python?
I first thought you wanted the continue keyword, but that would of course get you the next line of input.
I think I'm stumped. When looping over the lines of a file, what exactly should happen if you continued the loop without getting a new line?
Do you want to inspect the line again? If so, I suggest adding an inner loop that runs until you're "done" with the input line, which you can then break out of, or use maybe the while-condition and a flag variable to terminate.
Simply create an iterator of your own that lets you push data back on the front of the stream so that you can give the loop a line that you want to see over again:
next_lines = []
def prependIterator(i):
while True:
if next_lines:
yield(next_lines.pop())
else:
yield(i.next())
for sLine in prependIterator(oFile):
if ... some logic ... :
sLine = oFile.next()
... some more logic ...
# put the line back so that it gets read
# again as we head back up to the "for
# statement
next_lines.append(sLine)
If the prepend_list is never touched, then the prependIterator behaves exactly like whatever iterator it is passed: the if statement inside will always get False and it will just yield up everything in the iterator it has been passed. But if items are placed on the prepend_list at any point during the iteration, then those will be yielded first instead before it returns back to reading from the main iterator.
What you need is a simple, deterministic finite state machine. Something like this...
state = 1
for sLine in oFile:
if state == 1:
if ... some logic ... :
state = 2
elif state == 2:
if ... some logic ... :
state = 1
Ugly. Wrap the body in another loop.
for sLine in oFile :
while 1:
if ... some logic ... :
sLine = oFile.next()
... some more logic ...
continue
... some more logic ...
break
A little better:
class pushback_iter(object):
def __init__(self,iterable):
self.iterator = iter(iterable)
self.buffer = []
def next(self):
if self.buffer:
return self.buffer.pop()
else:
return self.iterator.next()
def __iter__(self):
return self
def push(self,item):
self.buffer.append(item)
it_file = pushback_iter(file)
for sLine in it_file:
if ... some logic ... :
sLine = it_file.next()
... some more logic ...
it_file.push(sLine)
continue
... some more logic ...
Unfortunately no simple way of referencing the current iterator.
Instead of looping through the file line by line, you can do a file.readlines() into a list. Then loop through the list (which allows you to look at the next item if you want). Example:
list = oFile.readlines()
for i in range(len(list))
#your stuff
list[i] #current line
list[i-1] #previous line
list[i+1] #next line
you can go to the previous or next line by simply using [i-1] or [i+1]. You just need to make sure that no matter what, i does not go out of range.
You just need to create a variable out of your iterator, and then manipulate that:
% cat /tmp/alt-lines.py
#! /usr/bin/python -tt
import sys
lines = iter(open(sys.argv[1]))
for line in lines:
print line,
lines.next()
% cat /tmp/test
1
2
3
4
% /tmp/alt-lines.py /tmp/test
1
3
...note that in this case we unconditionally do lines.next() so the above fails for files with odd lines, but I assume that isn't going to be the case for you (and adding the error checking is fairly trivial -- just catch and throw away StopIteration on the manual .next()).
You can assign your iterator to an variable then use the .next get te next one.
iter = oFile.xreadlines() # is this the correct iterator you want?
try:
sLine = iter.next()
while True:
if ... some logic ... :
sLine = iter.next()
... some more logic ...
continue
sLine = iter.next()
except StopIterator:
pass
jle's approach should work, though you might as well use enumerate():
for linenr, line in enumerate(oFile):
# your stuff

Categories

Resources