5

In Python, a list of strings can be joined together by

','.join(['ab', 'c', 'def'])

But how could I easily join a list of numbers or some other things? Like this:

0.join([1, 2, 3])  --->  [1, 0, 2, 0, 3]

Now I have to do this:

sum([[x, 0] for x in [1, 2, 3]], [])[:-1]
SaltyEgg
  • 1,498
  • 1
  • 15
  • 26
  • 10
    Short answer: Nope. – Martijn Pieters Apr 01 '14 at 13:56
  • 6
    Note that what you're describing is a different operation: `str.join` turns a list-of-strings into a string by interleaving and concatenating, your generalized join would turn a list-of-x into a list-of-x by only interleaving and not concatenating. The concatenation part is the whole reason `join` is a string method instead of a list method. –  Apr 01 '14 at 13:58
  • 1
    You probably want `[0].join([[1,2,3], [4,5], [6,7,8]])` to represent the same function. – ssm Apr 01 '14 at 14:08
  • 1
    As a note - your example code uses `sum()` to join lists - this is generally a really bad idea as `sum()` isn't optimised for the task. Take a look at RemcoGerlich's generator for the best way to do this. For a general case of joining many lists - you want [`itertools.chain()`](https://docs.python.org/3/library/itertools.html#itertools.chain) (use `list()` on the resuling generator if you need a list). – Gareth Latty Apr 01 '14 at 14:11

5 Answers5

5

You could make one:

def join_generator(joiner, iterable):
    i = iter(iterable)
    yield next(i)  # First value, or StopIteration

    while True:
       # Once next() raises StopIteration, that will stop this
       # generator too.
       next_value = next(i)
       yield joiner
       yield next_value

joined = list(join_generator(0, [1, 2, 3, 4]))
RemcoGerlich
  • 30,470
  • 6
  • 61
  • 79
  • Note you could just do `yield next(i)` initially (before entering the `while` loop), no need to assign to `next_value` - other than that, a nice implementation. – Gareth Latty Apr 01 '14 at 14:07
  • 1
    Pah! We need more one-liners! Everybody loves one-liners! `itertools.islice(itertools.chain.from_iterable(itertools.izip(itertools.repeat(joiner), iterable)), 1, None)` – sloth Apr 01 '14 at 14:17
  • @DominicKexel And this isn't a separate answer because? It's sufficiently different from he posted answer. – SethMMorton Apr 01 '14 at 14:32
  • Semantics of StopIteration changed around Python 3.3. See https://stackoverflow.com/a/14183847/2160256. So the above answer does no longer work but is trivially modifyable: just wrap the `next` calls into try/except and return in case of exception. – Marti Nito Jan 06 '22 at 09:35
2

Just because everybody loves unreadable one-liners:

import itertools

def join(sep, col):
    return itertools.islice(itertools.chain.from_iterable(itertools.izip(itertools.repeat(sep), col)), 1, None)

P.S.: better use RemcoGerlich's answer. It's way more readable.

Community
  • 1
  • 1
sloth
  • 99,095
  • 21
  • 171
  • 219
0

Not the way you are wanting to do it. You could write a for loop for the sum or you could write a for loop and have each item added as you go through your list. Otherwise, you won't be able to make the adjustment you're looking for.

Bmart15
  • 11
  • 4
0

As everyone is telling you, join is a string method instead of a list method.

But you can always do:

[int(x) for x in '0'.join(map(str, [1, 2, 3]))]
0

For newer python versions the following should do

def join(joiner, iterable):
    """Small helper that does similar things as "foo".join("bar") """
    it = iter(iterable)
    head, tail = next(it, None), it
    if head is not None:
        yield head

    for item in tail:
        yield joiner
        yield item


assert list(join("a", range(4))) == [0, "a", 1, "a", 2, "a", 3]
assert list(join("a", [])) == []
assert list(join("a", [0])) == [0]

Did I miss some corner case?

Marti Nito
  • 697
  • 5
  • 17