[Tutor] How do I (idiomatically) determine when I'm looking at the last entry in a list?

2015-10-28 Thread Flynn, Stephen (L & P - IT)
Afternoon,

Python 3.

I'm iterating through a list and I'd like to know when I'm at
the end of the said list, so I can do something different. For example

list_of_things = ['some', 'special', 'things']
for each_entry in list_of_things:
print(each_entry)
if each_entry == list_of_things[-1]: # do something special to
last entry
...etc


Is this the idiomatic way to detect you're at the last entry in a list
as you iterate through it?



For context, I'm working my way through a (csv) file which describes
some database tables. I'm building the Oracle DDL to create that table
as I go. When I find myself building the last column, I want to finish
the definition with a ");" rather than the usual "," which occurs at the
end of all other column definitions...

e.g.
CREATE TABLE wibble
(
Col1CHAR(2),
Col2NUMBER(5,2),
);

Regards,

Steve.


This email is security checked and subject to the disclaimer on web-page: 
http://www.capita.co.uk/email-disclaimer.aspx
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How do I (idiomatically) determine when I'm looking at the last entry in a list?

2015-10-28 Thread Peter Otten
Flynn, Stephen (L & P - IT) wrote:

> Afternoon,
> 
> Python 3.
> 
> I'm iterating through a list and I'd like to know when I'm at
> the end of the said list, so I can do something different. For example
> 
> list_of_things = ['some', 'special', 'things']
> for each_entry in list_of_things:
> print(each_entry)
> if each_entry == list_of_things[-1]: # do something special to
> last entry
> ...etc
> 
> 
> Is this the idiomatic way to detect you're at the last entry in a list
> as you iterate through it?

If the list is small you can slice it:

assert items
for item in things[:-1]:
   print(item, ",", sep="")
print(items[-1])

I have written a generator similar to

>>> def g(items):
... items = iter(items)
... try: 
... prev = next(items)
... except StopIteration: 
... return
... for item in items:
... yield False, prev
... prev = item
... yield True, prev
... 
>>> for islast, item in g("abc"):
... print(item, "(done)" if islast else "(to be continued)", sep="")
... 
a(to be continued)
b(to be continued)
c(done)

but only used it once ore twice.

> For context, I'm working my way through a (csv) file which describes
> some database tables. I'm building the Oracle DDL to create that table
> as I go. When I find myself building the last column, I want to finish
> the definition with a ");" rather than the usual "," which occurs at the
> end of all other column definitions...
> 
> e.g.
> CREATE TABLE wibble
> (
> Col1  CHAR(2),
> Col2  NUMBER(5,2),
> );

This particular problem can idiomatically be addressed with str.join():

>>> print(",\n".join(["foo", "bar", "baz"]))
foo,
bar,
baz



___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How do I (idiomatically) determine when I'm looking at the last entry in a list?

2015-10-28 Thread Cameron Simpson

On 28Oct2015 14:48, Flynn, Stephen (L & P - IT)  
wrote:

Python 3.

I'm iterating through a list and I'd like to know when I'm at
the end of the said list, so I can do something different. For example

list_of_things = ['some', 'special', 'things']
for each_entry in list_of_things:
print(each_entry)
if each_entry == list_of_things[-1]: # do something special to
last entry
...etc

Is this the idiomatic way to detect you're at the last entry in a list
as you iterate through it?


If it really is a list then enumerate is your friend.

 list_of_things = ['some', 'special', 'things']
 last_index = len(list_of_things) - 1
 for index, each_entry in enumerate(list_of_things):
   print(each_entry)
   if index == last_index:
 ... special stuff for the last index ...


For context, I'm working my way through a (csv) file which describes
some database tables. I'm building the Oracle DDL to create that table
as I go. When I find myself building the last column, I want to finish
the definition with a ");" rather than the usual "," which occurs at the
end of all other column definitions...


This is a bit different, in that you are probably not using a list: you don't 
know how long the sequence is.


I build things like that this way:

 fp.write('CREATE TABLE wibble\n(')
 sep = '\n   '
 for item in items:
   fp.write(sep)
   fp.write(... column definition for item ...)
   sep = ',\n   '
 fp.write('\n);\n')

i.e. instead of printing the separator _after_ each item, print it _before_.  
That way you can special case the first occasion and use a comma for each 
successive occasion.


Cheers,
Cameron Simpson 

Why is it whatever we don't understand is called a 'thing'? - "Bones" McCoy
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How do I (idiomatically) determine when I'm looking at the last entry in a list?

2015-10-28 Thread Steven D'Aprano
On Wed, Oct 28, 2015 at 02:48:05PM +, Flynn, Stephen (L & P - IT) wrote:

>   I'm iterating through a list and I'd like to know when I'm at
> the end of the said list, so I can do something different. For example
> 
> list_of_things = ['some', 'special', 'things']
> for each_entry in list_of_things:
>   print(each_entry)
>   if each_entry == list_of_things[-1]: # do something special to
> last entry
>   ...etc
> 
> 
> Is this the idiomatic way to detect you're at the last entry in a list
> as you iterate through it?

But it doesn't detect the last entry. Consider:

list_of_things = ["cheese", "fruit", "cheese", "fish", "cheese"]

Your code will perform the special processing three times.

There's no idiomatic way to do this because it is a fairly unusual thing 
to do. Normally we want to process all the items in a list the same way. 
But here are some solutions:

(1) Avoid the problem altogether by arranging matters so that the "last 
item" isn't in the list at all.

list_of_things = ['some', 'special']
last = 'things'
for each_entry in list_of_things:
print(each_entry)

print(last.upper())


(2) Slicing. Requires a little extra memory, but is probably the closest 
to an idiomatic solution for this sort of thing.

list_of_things = ['some', 'special', 'things']
for each_entry in list_of_things[:-1]:
print(each_entry)

print(list_of_things[-1].upper())


(3) Add a sentinel to the list.

list_of_things = ['some', 'special', None, 'things']
for each_entry in list_of_things:
if each_entry is None: break
print(each_entry)

print(list_of_things[-1].upper())


(4) Count the items.

list_of_things = ['some', 'special', 'things']
for i, each_entry in enumerate(list_of_things):
if i == len(list_of_things) - 1:  # Watch out for off-by-one errors!
each_entry = each_entry.upper()
print(each_entry)


(5) What if you're dealing with an iterable of unknown length that can't 
be sliced? The obvious answer is to convert to a list:

list_of_things = list(things)

but suppose you have some reason for not wanting to do that. (Perhaps 
things is truly huge, billions of items.) Something like this should 
help:

prev = []
for this in things:
if prev:
print(prev[0])
prev = [this]

print(prev[0].upper())


We can make this a little more efficient if things is an actual 
iterator:

things = iter(things)
try:
prev = next(things)
except StopIteration:
# No things at all.
pass
else:
for this in things:
print(prev)
prev = this
print(prev.upper())



-- 
Steve
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How do I (idiomatically) determine when I'm looking at the last entry in a list?

2015-10-28 Thread Steven D'Aprano
Wait, I have another comment...

On Wed, Oct 28, 2015 at 02:48:05PM +, Flynn, Stephen (L & P - IT) wrote:

>   I'm iterating through a list and I'd like to know when I'm at
> the end of the said list, so I can do something different. For example
[...]
> For context, I'm working my way through a (csv) file which describes
> some database tables. I'm building the Oracle DDL to create that table
> as I go. When I find myself building the last column, I want to finish
> the definition with a ");" rather than the usual "," which occurs at the
> end of all other column definitions...

Then you don't need to know when you're at the end of the list. See 
below.

But firstly, and MOST IMPORTANTLY, how are you sanitizing your input?

http://bobby-tables.com/

Code injection attacks are now #1 risk factor for code, above buffer 
overflows.

So, assuming you have sanitized your input, or trust it more than you 
trust your own code (you run tests on your own code, right?), let's see 
how to build up a string like:

"FUNCTION(a,b,c,d,e);"

with some variable number of string arguments a, b, c, ... 


args = ["5", "2", "7", "1", "0", "3"]
result = "FUNCTION(%s);" % ','.join(args)


This will do the right thing whether there is one argument or twenty, or 
even no arguments at all.

The "join" method inserts the first string *between* each of the list 
items. It deals correctly with the "no items" and "one item" cases:

py> "--".join([])
''
py> "--".join(["spam"])
'spam'
py> "--".join(["spam", "eggs"])
'spam--eggs'
py> "--".join(["spam", "eggs", "cheese"])
'spam--eggs--cheese'


so you don't have to worry about counting items or determining the last 
item, you just join them. 


-- 
Steve
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor