Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grammatical List Join in Python [duplicate]

Tags:

python

list

What's the most pythonic way of joining a list so that there are commas between each item, except for the last which uses "and"?

["foo"] --> "foo"
["foo","bar"] --> "foo and bar"
["foo","bar","baz"] --> "foo, bar and baz"
["foo","bar","baz","bah"] --> "foo, bar, baz and bah"
like image 333
user1277170 Avatar asked Nov 07 '13 14:11

user1277170


4 Answers

This expression does it:

print ", ".join(data[:-2] + [" and ".join(data[-2:])]) 

As seen here:

>>> data     ['foo', 'bar', 'baaz', 'bah'] >>> while data: ...     print ", ".join(data[:-2] + [" and ".join(data[-2:])]) ...     data.pop() ... foo, bar, baaz and bah foo, bar and baaz foo and bar foo 
like image 114
Matt Anderson Avatar answered Oct 12 '22 22:10

Matt Anderson


Try this, it takes into consideration the edge cases and uses format(), to show another possible solution:

def my_join(lst):     if not lst:         return ""     elif len(lst) == 1:         return str(lst[0])     return "{} and {}".format(", ".join(lst[:-1]), lst[-1]) 

Works as expected:

 my_join([]) => ""  my_join(["x"]) => "x"  my_join(["x", "y"]) => "x and y"  my_join(["x", "y", "z"]) => "x, y and z" 
like image 20
Óscar López Avatar answered Oct 13 '22 00:10

Óscar López


The fix based on the comment led to this fun way. It assumes no commas occur in the string entries of the list to be joined (which would be problematic anyway, so is a reasonable assumption.)

def special_join(my_list):
    return ", ".join(my_list)[::-1].replace(",", "dna ", 1)[::-1]


In [50]: def special_join(my_list):
        return ", ".join(my_list)[::-1].replace(",", "dna ", 1)[::-1]
   ....:

In [51]: special_join(["foo", "bar", "baz", "bah"])
Out[51]: 'foo, bar, baz and bah'

In [52]: special_join(["foo"])
Out[52]: 'foo'

In [53]: special_join(["foo", "bar"])
Out[53]: 'foo and bar'
like image 43
ely Avatar answered Oct 13 '22 00:10

ely


Already good answers available. This one works in all test cases and is slightly different than some others.

def grammar_join(words):
    return reduce(lambda x, y: x and x + ' and ' + y or y,
                 (', '.join(words[:-1]), words[-1])) if words else ''

tests = ([], ['a'], ['a', 'b'], ['a', 'b', 'c'])
for test in tests:                                 
    print grammar_join(test)

a
a and b
a, b and c
like image 32
doog abides Avatar answered Oct 12 '22 23:10

doog abides