Reputation: 13
I have something like this:
for i in range(0,100,5):
text = ("Price\t",
foo[i+0].bar, "\t",
foo[i+1].bar, "\t",
foo[i+2].bar, "\t",
foo[i+3].bar, "\t",
foo[i+4].bar, "\t",
"Value", "\n")
file.writelines(text)
My problem is: let's assume that i=0
. For that case, it is certain that I will have foo[0]. But for indices 1,2,3,4 foo can be empty. For example, if foo is empty for indices greater than 2, I want my text to be like:
text = ("Price\t",
foo[0].bar, "\t",
foo[1].bar, "\t",
foo[2].bar, "\n")
I thought of using exceptions, but I guess, I will not be able to construct text
if I do not have all the indexed elements. (Iteration will stop?) So, what is the best practice to do that? I could not think of a short way to do it. Basically what I need is:
text= ("Price\t",
ifexist(foo[0].bar, "\t"),
ifexist(foo[1].bar, "\t"),
ifexist(foo[2].bar, "\t"),
ifexist(foo[3].bar, "\t"),
ifexist(foo[4].bar, "\t"),
"Value", "\n")
ps: Please do not forget I assumed i=0
for the sake of simplicity. But in fact, generally I am going to have more than hundred values.
edit: By saying "can be empty", I meant to say that the index might be beyond the size of the list.
edit2: Abot foo:
# start class
class Test:
def __init__(self, bar, bar2, bar3):
self.bar= a
self.bar2= b
self.bar3= c
# end class
for i in particular_list:
# read and parse the input file with indeces obtained from particular_list
# do calculations for temp_bar,temp_bar2,temp_bar3
foo.append(Test(temp_bar, temp_bar2, temp_bar3))
Upvotes: 1
Views: 126
Reputation: 43533
It depends on what foo
is. If it is a list
or tuple
, there will be no empty indices. If it is a dict
, referencing an unknown key will result in a KeyError
exception.
Assuming foo
is a list of tuples, you can easily print it;
In [3]: t = range(30)
In [4]: p = [tuple(t[i:i+3]) for i in range(0, len(t), 4)]
In [5]: p
Out[5]: [(0, 1, 2), (4, 5, 6), (8, 9, 10), (12, 13, 14), (16, 17, 18), (20, 21, 22), (24, 25, 26), (28, 29)]
You can iterate over that list of tuples and print them;
In [6]: for k in p:
print '\t'.join(['Price'] + [str(i) for i in k] + ['Value'])
...:
Price 0 1 2 Value
Price 4 5 6 Value
Price 8 9 10 Value
Price 12 13 14 Value
Price 16 17 18 Value
Price 20 21 22 Value
Price 24 25 26 Value
Price 28 29 Value
Upvotes: 0
Reputation: 63757
My suggestion would be, do not rely on indices but rather structure your code around your data. If you are not indexing, then you would never have issues in IndexError
Consider A List L
of size N
to be divided evenly of size n
. This problem has various accepted solutions and approaches
The one I generally preach (though you are free to accept any of the alternate approaches) is
izip_longest(*[iter(L)]*n)
So Given a List
L = [a1, a2, a3 ... aN]
This will generate ⌊N/n⌋ equally sized chunks. The last shorter lists of size Mod(N, n)
would be appended by a filler, default in this case is None
L = [[a1, a2, a3 ... an],[a1, a2, a3 ... an],[a1, a2, a3 ... an],.(N Items)..[a1, a2, .. aN%n],None,None.. (n terms)]
Now just iterate through this list of lists ignorining any Nones
in the sublists
Demo
from itertools import izip_longest
class Foo(object):
def __init__(self, n):
self.bar = n
foo = [Foo(i) for i in range(12)]
for rows in izip_longest(*[iter(foo)]*5):
print "Price\t{}".format('\t'.join(str(row.bar)
for row in rows
if row is not None))
Output
Price 0 1 2 3 4
Price 5 6 7 8 9
Price 10 11
Upvotes: 1
Reputation: 122105
To expand on my comment, you could implement something like:
def if_exist(seq, index, attr, default):
"""Return seq[index].attr or default."""
try:
return getattr(seq[index], attr)
except IndexError:
return default
Which you could use like:
if_exist(foo, 0, "bar", "\t")
A demo:
>>> if_exist([1, 2, 3], 4, "bar", "\n")
'\n'
However, I suspect this to be an XY problem - if you provide more background information, it is likely that we can help you come up with a different approach that removes this issue entirely.
Upvotes: 0
Reputation: 1123640
You would take a different approach; you'd slice the original list, and use the csv
module to handle tab-delimiting and newlines:
import csv
with open('outputfile', 'w', newline='') as file:
writer = csv.writer(file, delimiter='\t')
for i in range(0, 100, 5):
row = foo[i:i + 5]
writer.writerow(['Price'] + row + ['Value'])
Slicing on a list always returns a new list object, but if you use slice indices outside the valid range the result is a shorter or empty list:
>>> foo = ['spam', 'ham', 'eggs']
>>> foo[0:5]
['spam', 'ham', 'eggs']
>>> foo[5:10]
[]
The csv.writer()
object, meanwhile, takes care of writing the list as a tab-delimited string, plus a newline, to your file.
Instead of using the csv
module, you would still use slicing, but make use of other techniques that take arbitrary lists of elements. str.join()
for example:
'\t'.join(['Price'] + foo[i:i + 5] + ['Value']) + '\n'
would produce one string of tab-delimited values, with a newline appended. This does require that all values in the list passed to str.join()
are already strings.
Upvotes: 2