how to join array of integers?

S

Summercool

i think in Ruby, if you have an array (or list) of integers

foo = [1, 2, 3]

you can use foo.join(",") to join them into a string "1,2,3"

in Python... is the method to use ",".join() ? but then it must take
a list of strings... not integers...

any fast method?
 
M

Marc 'BlackJack' Rintsch

i think in Ruby, if you have an array (or list) of integers

foo = [1, 2, 3]

you can use foo.join(",") to join them into a string "1,2,3"

in Python... is the method to use ",".join() ? but then it must take
a list of strings... not integers...

any fast method?

Convert them to strings before joining:

In [145]: foo = [1, 2, 3]

In [146]: ','.join(map(str, foo))
Out[146]: '1,2,3'

Ciao,
Marc 'BlackJack' Rintsch
 
J

John Machin

i think in Ruby, if you have an array (or list) of integers

foo = [1, 2, 3]

you can use foo.join(",") to join them into a string "1,2,3"

in Python... is the method to use ",".join() ? but then it must take
a list of strings... not integers...

any fast method?
foo = [1,2,3]
",".join(str(x) for x in foo) '1,2,3'
",".join(map(str, foo)) '1,2,3'

If you are going to write several such results to a file, consider
using the csv module.

HTH,
John
 
A

Arnau Sanchez

js escribió:
> print ''.join([str(i) for i in [1,2,3]])

It's better to use generator comprehension instead of LC:

",".join(str(i) for i in [1, 2, 3])

Or, if you happen to like the itertools modules:

from itertools import imap
",".join(imap(str, [1, 2, 3]))
 
E

Erik Jones

js escribió:
print ''.join([str(i) for i in [1,2,3]])

It's better to use generator comprehension instead of LC:

",".join(str(i) for i in [1, 2, 3])

Why is that? That entire expression must be evaluated to obtain the
result, so what is the advantage of using a generator comprehension
v. a list comprehension?
 
G

Grant Edwards

print ''.join([str(i) for i in [1,2,3]])

It's better to use generator comprehension instead of LC:

",".join(str(i) for i in [1, 2, 3])

Why is that? That entire expression must be evaluated to obtain the
result, so what is the advantage of using a generator comprehension
v. a list comprehension?

The generator avoids creating the intermediate list -- it
generates the intermediate values on the fly. For short
sequences it probably doesn't matter much. For a very long
list it's probably noticable.
 
E

Erik Jones

in Python... is the method to use ",".join() ? but then it
must take a list of strings... not integers...

any fast method?
print ''.join([str(i) for i in [1,2,3]])

It's better to use generator comprehension instead of LC:

",".join(str(i) for i in [1, 2, 3])

Or, if you happen to like the itertools modules:

from itertools import imap
",".join(imap(str, [1, 2, 3]))

It's nice people have invented so many ways to spell the
builting "map" ;)
",".join(map(str,[1,2,3]))
'1,2,3'

IIRC, map's status as a builtin is going away.

Erik Jones

Software Developer | Emma®
(e-mail address removed)
800.595.4401 or 615.292.5888
615.292.0777 (fax)

Emma helps organizations everywhere communicate & market in style.
Visit us online at http://www.myemma.com
 
T

tokland

Grant Edwards ha escrito:
Or, if you happen to like the itertools modules:

from itertools import imap
",".join(imap(str, [1, 2, 3]))

It's nice people have invented so many ways to spell the
builting "map" ;)

Did you wonder why the Python developers bother to implement "imap" if
"map" was already there?
",".join(map(str,[1,2,3]))
'1,2,3'

Of course the result is the same, but "map" returns a list while
"itertools.imap" returns an iterator. Fortunately, "map" will become
lazy on Py3000:

http://mail.python.org/pipermail/python-3000/2007-August/009207.html

As you said, it won't be noticeable for short lists, but it's a good
programming practice to use generators instead of lists (if you don't
really need a list!)

arnau
 
R

Robert Kern

Grant said:
print ''.join([str(i) for i in [1,2,3]])
It's better to use generator comprehension instead of LC:

",".join(str(i) for i in [1, 2, 3])
Why is that? That entire expression must be evaluated to obtain the
result, so what is the advantage of using a generator comprehension
v. a list comprehension?

The generator avoids creating the intermediate list -- it
generates the intermediate values on the fly. For short
sequences it probably doesn't matter much. For a very long
list it's probably noticable.

Not true. str.join() creates a list from the iterator if it is not already a
list or a tuple. In Objects/stringobject.c, look at string_join(); it calls
PySequence_Fast() on the argument. Looking in Objects/abstract.c, we see that
PySequence_Fast() short-circuits lists and tuples but builds a full list from
the iterable otherwise.

map() seems to reliably be the fastest option, and list comprehensions seem to
slightly edge out generator comprehensions if you do the timings.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
 
G

Grant Edwards

Grant said:
print ''.join([str(i) for i in [1,2,3]])
It's better to use generator comprehension instead of LC:

",".join(str(i) for i in [1, 2, 3])
Why is that? That entire expression must be evaluated to
obtain the result, so what is the advantage of using a
generator comprehension v. a list comprehension?

The generator avoids creating the intermediate list -- it
generates the intermediate values on the fly. For short
sequences it probably doesn't matter much. For a very long
list it's probably noticable.

Not true. str.join() creates a list from the iterator if it is
not already a list or a tuple.

So the iterator avoids creating an intermediate list, but the
join method goes ahead and does it anyway?
In Objects/stringobject.c, look at string_join(); it calls
PySequence_Fast() on the argument. Looking in
Objects/abstract.c, we see that PySequence_Fast()
short-circuits lists and tuples but builds a full list from
the iterable otherwise.

So what's the point of iterables if code is going to do stuff
like that when it wants to iterate over a sequence?
map() seems to reliably be the fastest option,

Which is apparently going away in favor of the slower iterator
approach?
 
S

Steven D'Aprano

js escribió:
print ''.join([str(i) for i in [1,2,3]])

It's better to use generator comprehension instead of LC:

",".join(str(i) for i in [1, 2, 3])


Really? Why do you say that a generator expression is "better" than a
list comprehension?

import timeit
timeit.Timer("', '.join([str(i) for i in [1,2,3]])", "").repeat() [5.0969390869140625, 4.5353701114654541, 4.5807528495788574]
timeit.Timer("', '.join(str(i) for i in [1,2,3])", "").repeat()
[11.651727914810181, 10.635221004486084, 10.522483110427856]

The generator expression takes about twice as long to run, and in my
opinion it is no more readable. So what's the advantage?

Or, if you happen to like the itertools modules:

from itertools import imap
",".join(imap(str, [1, 2, 3]))
timeit.Timer("', '.join(imap(str, [1,2,3]))",
.... "from itertools import imap").repeat()
[9.3077328205108643, 8.655829906463623, 8.5271010398864746]

Faster than a generator expression, but still pretty slow.
 
S

Steven D'Aprano

It's nice people have invented so many ways to spell the builting "map"
;)
",".join(map(str,[1,2,3]))
'1,2,3'


The oldest solution, and if not the fastest, at least neck-and-neck with
the list comprehension.
timeit.Timer("', '.join(map(str, [1,2,3]))", "").repeat()
[5.0320308208465576, 4.1513419151306152, 4.0970909595489502]


For those who missed my earlier post:

list comp, best of three for one million iterations: 4.53 seconds
generator expression: 10.52 seconds
itertools.imap: 8.52 seconds

Your mileage may vary.

I think it is a crying shame that Guido's prejudice against functional
programming seems to have increased over the years, instead of decreased.
Iterators are wonderful tools, but professional tradesmen use more than
one sort of hammer. (There are claw hammers and ball peen hammers and
tack hammers and wooden mallets and...)

"One obvious way to do it" should not mean "force everyone to use a tack
hammer to drive in nails, because it's the only hammer in the tool box".
It should mean "it's obvious, use the tack hammer to drive in tacks and
the claw hammer for carpentry and the wooden mallet for beating out dints
in sheet metal and..."
 
R

Robert Kern

Grant said:
Grant said:
print ''.join([str(i) for i in [1,2,3]])
It's better to use generator comprehension instead of LC:

",".join(str(i) for i in [1, 2, 3])
Why is that? That entire expression must be evaluated to
obtain the result, so what is the advantage of using a
generator comprehension v. a list comprehension?
The generator avoids creating the intermediate list -- it
generates the intermediate values on the fly. For short
sequences it probably doesn't matter much. For a very long
list it's probably noticable.
Not true. str.join() creates a list from the iterator if it is
not already a list or a tuple.

So the iterator avoids creating an intermediate list, but the
join method goes ahead and does it anyway?
Yup.
In Objects/stringobject.c, look at string_join(); it calls
PySequence_Fast() on the argument. Looking in
Objects/abstract.c, we see that PySequence_Fast()
short-circuits lists and tuples but builds a full list from
the iterable otherwise.

So what's the point of iterables if code is going to do stuff
like that when it wants to iterate over a sequence?

Some code dealing with sequences can be recast in terms of iterators of unknown
length. Some can't. Some are better cast in terms of iterators than sequences;
some aren't.
Which is apparently going away in favor of the slower iterator
approach?

It's only slower in this case. Of course, the main difference is where the loop
takes place, in C or in Python. imap() appears to give the same performance as
map().

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
 
P

Paul Rudin

Steven D'Aprano said:
js escribió:
On 9/15/07, Summercool <[email protected]> wrote:
in Python... is the method to use ",".join() ? but then it must take
a list of strings... not integers...

any fast method?
print ''.join([str(i) for i in [1,2,3]])

It's better to use generator comprehension instead of LC:

",".join(str(i) for i in [1, 2, 3])


Really? Why do you say that a generator expression is "better" than a
list comprehension?

import timeit
timeit.Timer("', '.join([str(i) for i in [1,2,3]])", "").repeat() [5.0969390869140625, 4.5353701114654541, 4.5807528495788574]
timeit.Timer("', '.join(str(i) for i in [1,2,3])", "").repeat()
[11.651727914810181, 10.635221004486084, 10.522483110427856]

The generator expression takes about twice as long to run, and in my
opinion it is no more readable. So what's the advantage?

If you do it with a decent size list they take more or less the same
time. You'd presumably expect the generator to use less memory; which
might be an advantage if you have large lists.

Isn't it odd that the generator isn't faster, since the comprehension
presumably builds a list first and then iterates over it, whereas the
generator doesn't need to make a list?
 
A

Alex Martelli

Paul Rudin said:
Isn't it odd that the generator isn't faster, since the comprehension
presumably builds a list first and then iterates over it, whereas the
generator doesn't need to make a list?

The generator doesn't, but the implementation of join then does
(almost). See Objects/stringobject.c line 1745:

seq = PySequence_Fast(orig, "");

As per <http://docs.python.org/api/sequence.html>,
"""
PyObject* PySequence_Fast(PyObject *o, const char *m)

Return value: New reference.

Returns the sequence o as a tuple, unless it is already a tuple or list,
in which case o is returned. Use PySequence_Fast_GET_ITEM() to access
the members of the result. Returns NULL on failure. If the object is not
a sequence, raises TypeError with m as the message text.
"""

If orig is neither a list nor a tuple, but for example a generator,
PySequence_Fast builds a list from it (even though its docs which I just
quoted says it builds a tuple -- building the list is clearly the right
choice, so I'd say it's the docs that are wrong, not the code;-)... so
in this particular case the usual advantage of the generator disappears.

PySequence_fast is called in 13 separate spots in 8 C files in the
Python 2.5 sources, so there may a few more surprises like this;-).


Alex
 
S

Steven D'Aprano

If you do it with a decent size list they take more or less the same
time.

Did you try it, or are you guessing? What do you call a decent size?

You'd presumably expect the generator to use less memory; which
might be an advantage if you have large lists.

Unfortunately, Python doesn't make it as easy to measure memory use as it
does to time snippets of code, so that's just a hypothetical.

Isn't it odd that the generator isn't faster, since the comprehension
presumably builds a list first and then iterates over it, whereas the
generator doesn't need to make a list?

Who says it doesn't need to make a list? string.join() needs a sequence.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top