Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concatenating Strings from a List of Objects

I know that the pythonic way of concatenating a list of strings is to use

l =["a", "b", "c"]
"".join(l)

But how would I do this if I have a list of objects which contain a string (as an attribute), without reassigning the string?

I guess I could implement __str__(self). But that's a workaround that I would prefer not to use.

like image 397
Mac C. Avatar asked Jun 15 '17 14:06

Mac C.


4 Answers

I guess the most pythonic way to do this would be using generator expression / list comprehension. If the string for example is an attribute of the object obj_instance.str_attr then just run:

"".join(x.str_attr for x in l)

or

"".join([x.str_attr for x in l])

edited: see discussion on the performance below (they claim that list comprehension - 2nd option is faster).

like image 200
Dimgold Avatar answered Oct 25 '22 10:10

Dimgold


What about something like :

joined = "".join([object.string for object in lst_object])
like image 31
Pablo Avatar answered Oct 25 '22 09:10

Pablo


The performance difference between generator expression and list comprehension is easy to measure:

python --version && python -m timeit -s \
  "import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
   "''.join(obj.a for obj in l)"
Python 2.7.12
10 loops, best of 3: 87.2 msec per loop

python --version && python -m timeit -s \
  "import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
   "''.join([obj.a for obj in l])"
Python 2.7.12
10 loops, best of 3: 77.1 msec per loop

python3.4 --version && python3.4 -m timeit -s \
  "import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
   "''.join(obj.a for obj in l)"
Python 3.4.5
10 loops, best of 3: 77.4 msec per loop

python3.4 --version && python3.4 -m timeit -s \
  "import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
   "''.join([obj.a for obj in l])"
Python 3.4.5
10 loops, best of 3: 66 msec per loop

python3.5 --version && python3.5 -m timeit -s \
  "import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
   "''.join(obj.a for obj in l)"
Python 3.5.2
10 loops, best of 3: 82.8 msec per loop

python3.5 --version && python3.5 -m timeit -s \
  "import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
   "''.join([obj.a for obj in l])"
Python 3.5.2
10 loops, best of 3: 64.9 msec per loop

python3.6 --version && python3.6 -m timeit -s \
  "import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
   "''.join(obj.a for obj in l)"
Python 3.6.0
10 loops, best of 3: 84.6 msec per loop

python3.6 --version && python3.6 -m timeit -s \
  "import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
   "''.join([obj.a for obj in l])"
Python 3.6.0
10 loops, best of 3: 64.7 msec per loop

It turns out that list comprehension is consistently faster than generator expression:

  • 2.7: ~12% faster
  • 3.4: ~15% faster
  • 3.5: ~22% faster
  • 3.6: ~24% faster

But note that memory consumption for list comprehension is 2x.

Update

Dockerfile you can run on your hardware to get your results, like docker build -t test-so . && docker run --rm test-so.

FROM saaj/snake-tank

RUN echo '[tox] \n\
envlist = py27,py33,py34,py35,py36 \n\
skipsdist = True \n\
[testenv] \n\
commands = \n\
  python --version \n\
  python -m timeit -s \\\n\
    "import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \\\n\
    "str().join(obj.a for obj in l)" \n\
  python -m timeit -s \\\n\
    "import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \\\n\
    "str().join([obj.a for obj in l])"' > tox.ini
CMD tox
like image 35
saaj Avatar answered Oct 25 '22 11:10

saaj


You can convert all your string attributes to list of strings:

string_list = [myobj.str for myobj in l]

The code above creates list of strings using generator. Afterwards u would use a standard way to concatenate strings:

"".join(string_list)

like image 21
I3orn2FLY Avatar answered Oct 25 '22 10:10

I3orn2FLY