Concatenating strings from a list of objects

I know that the pythonic way of combining 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 that contain a string (as an attribute), without reinitializing the string?

I suppose I can implement __str__(self) , but this is a workaround that I would prefer not to use.

+5
source share
8 answers

I think the most pythonic way to do this would be to use a generator expression / list. If the string, for example, is an attribute of the obj_instance.str_attr object then simply run:

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

or

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

edited : see the performance discussion below (they argue that list comprehension is second option faster ).

+10
source

Sort of:

 joined = "".join([object.string for object in lst_object]) 
+4
source

The difference in performance between a generator expression and a 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 the 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 your equipment to get your results, for example docker build -t test-so . && docker run --rm test-so 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 
+4
source

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

string_list = [myobj.str for myobj in l]

The code above creates a list of strings using a generator. Subsequently, u will use the standard string concatenation method:

"".join(string_list)

+2
source

understanding the list may be helpful. for example, with a list of dictionaries,

 # data data = [ {'str': 'a', 'num': 1}, {'str': 'b', 'num': 2}, ] joined_string = ''.join([item['str'] for item in data]) 
+1
source

From previous answers:

 "".join([x.str_attr if hasattr(x,'str_attr_') else x for x in l ]) 

If your data type is simple.

 ''.join([somefunction(x) for x in l]) # 

See also the itertools module. Then you can check the filtering of values.

+1
source

Another possibility is to use functional programming:

 class StrObj: def __init__(self, str): self.str = str a = StrObj('a') b = StrObj('b') c = StrObj('c') l = [a,b,c] "".join(map(lambda x: x.str, l)) 

This will work in any way when a string can be associated with an object (directly as an attribute or in a more complex way). Only lambda needs to be adapted.

+1
source

Self-evident single-line

 "".join(str(d.attr) for d in l) 
+1
source

Source: https://habr.com/ru/post/1268872/


All Articles