views:

101

answers:

4

I need to concatenate string to an existing one as follows.

for k,v in r.iteritems():
    tableGenString += "%s %s, " % (k, what_type(v))

The problem is that for the last item the comma(',') should not be added.

How can I check if k,v is the last item?

Added

The example is a simplified version of the real code as follows.

for k,v in r.iteritems():
    filteredKey = m.mapper(k)
    (typestring, valuestring) = what_type(v)
    tableGenString += "%s %s, " % (k, typestring)
    string1 += "%s, " % k
    string2 += "%s, " % valuestring

I need to check the last item for this case.

+15  A: 

Don't build large strings with concatenation like that. Do this instead:

tableGenString = ', '.join('%s %s' % (k, what_type(v)) for k, v in r.iteritems())
FogleBird
heh...nothing like having "one obvious way to do it" :-)
jsbueno
@FogleBird: Your answer should work, but I need to find a way to find the last item as I added to my original question.
prosseek
@prosseek: No you dont. the "join" command is meant for exactly what you're trying to do. It will take an iterable and join the elements together with a separator (the string). So ", ".join(range(3)) will give "0, 1, 2".
Scott Stafford
@prosseek: And even if you really had to remove a final comma (which you don't, because Python is intelligently designed), you still wouldn't have to find the final element but could remove it from the concatenated string via slicing or .strip().
chryss
+1  A: 

Use the "join" string method instead of an outter for:

tableGenString = ", ".join ("%s %s" %(k, what_type(v) for k, v in r.iteritems())
jsbueno
You forgot the "join". :-)
Daniel Stutzbach
@Daniel: eeek :-)
jsbueno
+2  A: 

The OP insists in a comment:

I need to find a way to find the last item as I added to my original question

apparently for purposes other than clumsily duplicate the ', '.join correctly suggested in other answers.

Of course, the order in which keys and values are presented by iteritems (or any other way to iterate on a dict, which is a hash table and has no concept of "order", and therefore not of "first" or "last" either!) is totally arbitrary. Nevertheless, the last one (to be presented in this arbitrary order) can be identified:

for i, (k,v) in enumerate(r.iteritems()):
    if i == len(r) - 1:
        print "last item: key=%r, value=%r" % (k, v)

Similarly, once you get i from this kind of enumerate call, if i==0: will identify the first item, if i==len(r)//2: will identify the middle item, and so forth.

Alex Martelli
I think a better answer would encourage the asker not to use this silly scheme.
Jesse Dhillon
if you use this `for i,(k,v) in enumerate(r.iteritems(), 1-len(r)):` instead you can just check for `i == 0` to detect the last item
gnibbler
A: 

Ugh. If you'd like something that's readable instead of an overly-dense join, here:

def build_str(r):
    tableGenString = ""
    for k,v in r.iteritems():
        if tableGenString != "":
            tableGenString += ", "
        tableGenString += "%s %s" % (k, type(v))

    return tableGenString

Sample return value:

baz <type 'str'>, have a list <type 'list'>, foo <type 'int'>, bar <type 'str'>, or a tuple <type 'tuple'>

And lest someone complain that this is somehow slower than the join... it's not on my box:

import timeit

r = {
    "foo": 123,
    "bar": "456",
    "baz": "abcd",
    "have a list": [7, 8, "efgh"],
    "or a tuple": (9, 0, 10),
}

def build_str(r):
    tableGenString = ""
    for k,v in r.iteritems():
        if tableGenString != "":
            tableGenString += ", "
        tableGenString += "%s %s" % (k, type(v))

    return tableGenString

if __name__ == '__main__':
    readable_time = timeit.Timer("build_str(r)", "from __main__ import build_str, r").timeit()
    print "Readable time: %f" % (readable_time,)

    join_time = timeit.Timer("', '.join('%s %s' % (k, type(v)) for k, v in r.iteritems())", "from __main__ import r").timeit()
    print "Join time: %f" % (join_time,)

...

$ python concat.py 
Readable time: 4.705579
Join time: 5.277732
$ 
Nicholas Knight
Sorry.,, 5 lines of extra code where a super-documented string method resolves in one line, is not what Python is for. The joins seens har dto read, but it is more due to the OP variable names (k, v, and r) than any other thing.
jsbueno
@jsbueno: Last I checked, Python is for creating efficient, maintainable code. Trying to make it look like Perl and require half the developers to go look something up to try to understand a simple concatenation operation is not efficient, and does not make for maintainable code.
Nicholas Knight
@jsbueno: Also, it's actually not about the .join() itself. A run of the mill .join() call bothers me not at all, it's embedding an ugly-ass mutant form of loop in it.
Nicholas Knight