Print a list of space-separated elements
Asked Answered
Z

4

54

I have a list L of elements, say natural numbers. I want to print them in one line with a single space as a separator. But I don't want a space after the last element of the list (or before the first).

In Python 2, this can easily be done with the following code. The implementation of the print statement (mysteriously, I must confess) avoids to print an extra space before the newline.

L = [1, 2, 3, 4, 5]
for x in L:
    print x,
print

However, in Python 3 it seems that the (supposedly) equivalent code using the print function produces a space after the last number:

L = [1, 2, 3, 4, 5]
for x in L:
    print(x, end=" ")
print()

Of course there are easy answers to my question. I know I can use string concatenation:

L = [1, 2, 3, 4, 5]
print(" ".join(str(x) for x in L))

This is a quite good solution, but compared to the Python 2 code I find it counter-intuitive and definitely slower. Also, I know I can choose whether to print a space or not myself, like:

L = [1, 2, 3, 4, 5]
for i, x in enumerate(L):
    print(" " if i>0 else "", x, sep="", end="")
print()

but again this is worse than what I had in Python 2.

So, my question is, am I missing something in Python 3? Is the behavior I'm looking for supported by the print function?

Zucker answered 21/3, 2014 at 10:38 Comment(2)
I think the join solution is bad because: (1) it explicitly uses str, which I find ugly and counter-intuitive, and most importantly (2) it first constructs a string and then prints it, which may be a bad idea if the list is long.Zucker
I'm not sure why @Braiam edited the title and removed "in Python 3". The original question, many years ago, was about a difference in practice between Python 2 and Python 3. Anyway...Zucker
V
150

You can apply the list as separate arguments:

print(*L)

and let print() take care of converting each element to a string. You can, as always, control the separator by setting the sep keyword argument:

>>> L = [1, 2, 3, 4, 5]
>>> print(*L)
1 2 3 4 5
>>> print(*L, sep=', ')
1, 2, 3, 4, 5
>>> print(*L, sep=' -> ')
1 -> 2 -> 3 -> 4 -> 5

Unless you need the joined string for something else, this is the easiest method. Otherwise, use str.join():

joined_string = ' '.join([str(v) for v in L])
print(joined_string)
# do other things with joined_string

Note that this requires manual conversion to strings for any non-string values in L!

Veliger answered 21/3, 2014 at 10:41 Comment(16)
This answers my question and is actually faster in Python 3 than the for loop. I'm puzzled, however, because in Python 3 this takes 2.5 sec. to print list(range(1000000)), whereas the original Python 2 for loop takes 0.36 sec. Did printing degrade so much in Python3?Zucker
@nickie: Did you include the list() call in your timings? It's not needed for any of the code you posted nor my answer. print() is also a function call now, which has more overhead than the print statement, and Python 3 also adds an encoding step (albeit in C code) from unicode to bytes.Veliger
No, I created the list beforehand in both versions. I can post code of the benchmark, if you find this interesting. In understand the overhead, but we're talking about almost an order of magnitude.Zucker
@Zucker in my benchmark: lst = range(100*1000) ; for i in lst: print i, took ~0.04s, while in python3 lst = range(100*1000) ; print(*lst) took ~0.08sAttend
@m.wasowski: I think the OP was using a loop in Python 3 as well.Veliger
for loop in Python 3 doubles time (to ~0.15s) on my boxAttend
@m.wasowski: range in Python 2 returns a list whereas in Python 3 a generator object. Anyway, the question was not primarily about performance and I feel reluctant to clutter it with benchmarking code. If you and/or Martijn think that continuing this discussion is interesting, I can post a new question. Thank you both, again.Zucker
I can reproduce a large increase in time in Python 3 for the for i in L: print(i, end=' ') loop, yes; about 4.5 times as much time over 10 repeats with timeit and stdout set to /dev/null. The difference lies in the function call (stack push and pop) and the more complex I/O structure (encoding unicode to bytes).Veliger
To a terminal the performance should be a non-issue, but if the target is a file, someone might be tempted to do something like print(*L, sep='\n', file=f) for a very large list. The issue here -- possibly (the list would have to be huge) -- is that the interpreter will create 2 tuples from list L that exist for the duration of the call.Counterpunch
We can also use join as in My answer.Mariammarian
@DeepakYadav: sure, but at the cost of creating a single larger string you then discard again, plus string objects for each and every value in the input list that isn't a string already. print(..) doesn't have to do most of that work, it just sends the data to the stdout buffer, which then can do any processing at the C level, and never has to create a new Python object in that process. That makes it all the more efficient.Veliger
Note that joining a generator expression should be faster than joining a list; that is ' '.join(str(v) for v in range(100*1000)) is faster than ' '.join([str(v) for v in range(100*1000)])Unpopular
@Unpopular It is not faster because string joining needs to know the total length up front and so makes two passes. To be able to do that a generator expression is consumed into a list first and so is slower. If you actually timed your two expressions you’ll find that your assertion doesn’t hold.Veliger
@Ben: see Raymond Hettinger’s answer for timing runs.Veliger
what is * called in this reference? and what is this printing suing * operator called? Could someone point me out to the documentation? Thank youMercurialism
@NithinGowda: That's part of the call expression syntax, and I call it argument expansion. It's not an operator.Veliger
R
10

Although the accepted answer is absolutely clear, I just wanted to check efficiency in terms of time.

The best way is to print joined string of numbers converted to strings.

print(" ".join(list(map(str,l))))

Note that I used map instead of loop. I wrote a little code of all 4 different ways to compare time:

import time as t

a, b = 10, 210000
l = list(range(a, b))
tic = t.time()
for i in l:
    print(i, end=" ")

print()
tac = t.time()
t1 = (tac - tic) * 1000
print(*l)
toe = t.time()
t2 = (toe - tac) * 1000
print(" ".join([str(i) for i in l]))
joe = t.time()
t3 = (joe - toe) * 1000
print(" ".join(list(map(str, l))))
toy = t.time()
t4 = (toy - joe) * 1000
print("Time",t1,t2,t3,t4)

Result:

Time 74344.76 71790.83 196.99 153.99

The output was quite surprising to me. Huge difference of time in cases of 'loop method' and 'joined-string method'.

Conclusion: Do not use loops for printing list if size is too large( in order of 10**5 or more).

Reset answered 18/2, 2019 at 19:47 Comment(0)
L
1
list = [1, 2, 3, 4, 5]
for i in list[0:-1]:
    print(i, end=', ')
print(list[-1])

do for loops really take that much longer to run?

was trying to make something that printed all str values in a list separated by commas, inserting "and" before the last entry and came up with this:

spam = ['apples', 'bananas', 'tofu', 'cats']
for i in spam[0:-1]:
    print(i, end=', ')
print('and ' + spam[-1])
Librettist answered 9/10, 2018 at 11:45 Comment(0)
S
1

Joining elements in a list space separated:

word = ["test", "crust", "must", "fest"]
word.reverse()
joined_string = ""
for w in word:
   joined_string = w + joined_string + " "
print(joined_string.rstrim())
Stitt answered 20/4, 2020 at 9:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.