A 2-dimensional (2D) list is simply a list of lists (lists within a list). Here are some examples of 2D lists in Python.
1 2 3 4 |
# A 2D list with items of varying sizes and different data types. lst1 = [["Python", "Java"],["Functions", "Classes"], [7, 8, 9]] # A 2D list with sublists of the same sizes and same data types. lst2 = [[3, 4], [5, 6], [7, 8]] |
In this article, we will discuss how to convert a 2D list into a Python string using different methods (later, we will test which of the methods is the fastest). All the methods discussed here will do the job in two steps:
- Flatten the list, that is, convert the 2D list into a 1D list, and
- Join the elements of the 1D array using the str.join() method.
The str.join() method
We will use this method for all the methods we will discuss. The str.join(iterable) is used to join the elements of the iterable (in our case, a 1D list) on str. Here is an example,
1 2 3 4 |
fruits = ["apple", "pineapple", "grape"] # Join the elements using the "*" character. joined = "*".join(fruits) print(joined) |
Output:
apple*pineapple*grape
Note that the elements of the iterable in str.join() must be string otherwise, the function will raise an error. We will deal with that in Method 2.
Let’s now discuss some methods to convert a 2D Python list into a string.
Method 1: Using for-loop or List Comprehension with str.join() function
There are two ways to use for-loop her. The first way is to work with nested for-loop, as shown below.
1 2 3 4 5 6 7 8 9 10 |
lst1 = [["Apple", "Orange"], ["Cow", "Goat"], ["Chicago", "Seattle", "Nebraska"]] # Create an empty list to hold the flattened list. flat_list = [] for sublist in lst1: for item in sublist: flat_list.append(item) print(flat_list) # Make a string by joining the items in the flat_list using the join() function str1 = " ".join(flat_list) print(str1) |
Output:
['Apple', 'Orange', 'Cow', 'Goat', 'Chicago', 'Seattle', 'Nebraska'] Apple Orange Cow Goat Chicago Seattle Nebraska
Alternatively, you can use the extend function to add elements of a sublist to the flat_list at once without looping over items individually.
1 2 3 4 5 6 7 8 |
lst1 = [["Apple", "Orange"], ["Cow", "Goat"], ["Chicago", "Seattle", "Nebraska"]] flat_list = [] for sublist in lst1: # Extend the flat_list with the items from the sublist. flat_list.extend(sublist) print(flat_list) str1 = " ".join(flat_list) print(str1) |
Output:
['Apple', 'Orange', 'Cow', 'Goat', 'Chicago', 'Seattle', 'Nebraska'] Apple Orange Cow Goat Chicago Seattle Nebraska
The for-loop approach can be reduced to a one-liner using the concept of list comprehension, as shown in the following example.
1 2 3 4 5 6 |
lst1 = [["Apple", "Orange"], ["Cow", "Goat"], ["Chicago", "Seattle", "Nebraska"]] # Using the list comprehension flat_list1 = [item for sublist in lst1 for item in sublist] # joining items on a flat list using "#" str2 = "#".join(flat_list1) print(str2) |
Output:
Apple#Orange#Cow#Goat#Chicago#Seattle#Nebraska
Method 2: Using itertools + str.join()
There are two functions in itertools that you can do to flatten a 2D list – itertools.chain() and itertools.chain.from_iterable(). Here are the examples,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import itertools lst2d = [["Python", "Java"], ["Functions", "Classes"], [7, 8, 9]] # Unpack the list elements using the "*" operator. lst1d = list(itertools.chain(*lst2d)) # The result is a 1D array of strings and integers. print(lst1d) # Since the str.join() function only accepts string types, we need to convert # the integers in lst1d to strings. The efficient way to do this is by using map() lst1d = list(map(str, lst1d)) print(lst1d) # Now, we can join the result using whitespace. str2 = " ".join(lst1d) print(str2) |
Output:
['Python', 'Java', 'Functions', 'Classes', 7, 8, 9] ['Python', 'Java', 'Functions', 'Classes', '7', '8', '9'] Python Java Functions Classes 7 8 9
The map(func, iterable) is a function efficiently used to apply function func in all the elements of the iterable. In the example above, we used it to convert each element of lst1d into a string.
The next example goes through the same steps as the previous one but now uses itertools.chain.from_iterable() instead of itertools.chain().
1 2 3 4 5 6 7 8 |
lst2 = [[3, 4], [5, 6], [7, 8]] # We need to pass the 2D list here - no need to unpack as we did before. flat_lst2 = list(itertools.chain.from_iterable(lst2)) # Convert elements of flat_list2 into strings flat_lst2 = list(map(str, flat_lst2)) # Join the resulting list str3 = "--".join(flat_lst2) print(str3) |
Output:
3--4--5--6--7--8
Method 3: Using the inbuilt sum() function and str.join()
Recall that the sum of two lists, A and B (say), in Python is equal to a list of all the elements in A and B, e.g., if A= [e1, e3] and B = [e2, e4], then A+B = [e1, e3, e2, e4]. We can also implement the addition with the sum(iterable, 0) function.
In the sum(iterable, 0) function, the first element is an iterable we want to sum (in our case, the 2D list), and the second element is the initial value of the sum (0 by default). We must change the initial value to an empty list because we will be “adding” lists. In that case, the sum([[1,3], [2,4]], []) will be [1, 3, 2, 4].
Here is a code example.
1 2 3 4 5 6 7 |
lst_2d = [["Apple", "Orange"], ["Cow", "Goat"], ["Chicago", "Seattle", "Nebraska"]] # "Summing" lst_2d joins all sublists. lst_1d = sum(lst_2d, []) print(lst_1d) # Joining elements into a string using str.join() str1 = "...".join(lst_1d) print(str1) |
Output:
['Apple', 'Orange', 'Cow', 'Goat', 'Chicago', 'Seattle', 'Nebraska'] Apple...Orange...Cow...Goat...Chicago...Seattle...Nebraska
Method 4: Using functools and operator modules
1 2 3 4 5 6 7 |
from functools import reduce import operator lst_2d = [["Apple", "Orange"], ["Cow", "Goat"], ["Chicago", "Seattle", "Nebraska"]] lst_1d = reduce(operator.iconcat, lst_2d, []) str2 = ";".join(lst_1d) print(str2) |
Output:
Apple;Orange;Cow;Goat;Chicago;Seattle;Nebraska
Method 5: Using NumPy Methods
We can use two methods here: numpy.concatenate(2d_list) or array.flat. The first method works when the sublists of our 2D list are of varying sizes, but the latter requires the sublists to be the same size. Let’s see some examples.
1 2 3 4 5 6 7 8 9 10 |
import numpy as np lst1 = [["Python", "Java"], ["Functions", "Classes"], [7, 8, 9]] # Use the np.concatenate function when the sublists on the # input list are not of equal size. # For example, sublists 1 and 2 in lst1 have 2 elements, but the third # has 3 elements. lst_1d = np.concatenate(lst1) str2 = " ".join(map(str, lst_1d)) print(str2) |
Output:
Python Java Functions Classes 7 8 9
1 2 3 4 5 6 7 8 |
import numpy as np lst1 = [["Python", "Java"], ["Functions", "Classes"], [7, 8]] # Use numpy_array.flat when the sublists on the input list are of # varying sizes. lst_1d = np.array(lst1).flat str2 = " ".join(map(str, lst_1d)) print(str2) |
Output:
Python Java Functions Classes 7 8
Which of the Methods is the Fastest?
The following code snippet can be used to test the speed of all the methods we discussed above using perfplot – a function that extends Python’s timeit functionality in conducting speed tests.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
from functools import reduce import operator import itertools import numpy as np import perfplot def forloop_extend(lst): flat_list = [] for sublist in lst: flat_list.extend(sublist) return " ".join(map(str, flat_list)) def forloop_nested(lst): flat_list = [] for sublist in lst: for item in sublist: flat_list.append(item) return " ".join(map(str, flat_list)) def list_comprehension(lst): return " ".join(map(str, [item for sublist in lst for item in sublist])) def sum_func(lst): return " ".join(map(str, sum(lst, []))) def functools_and_operator(lst): return " ".join(map(str, reduce(operator.iconcat, lst, []))) def itertools_chain(lst): return " ".join(map(str, itertools.chain(*lst))) def itertools_chain_iterable(lst): return " ".join(map(str, itertools.chain.from_iterable(lst))) def numpy_flat(lst): return " ".join(map(str, np.array(lst).flat)) def numpy_concatenate(lst): return " ".join(map(str, np.concatenate(lst))) benchmark = perfplot.bench( setup=lambda n: [list(range(7))] * n, kernels=[ forloop_extend, forloop_nested, list_comprehension, sum_func, functools_and_operator, itertools_chain, itertools_chain_iterable, numpy_concatenate, numpy_flat, ], n_range=[2**k for k in range(16)], xlabel="num lists (of length 7)", ) benchmark.save("speed_test_2.png") benchmark.show() |
The benchmarks show that Method 4 (using functools and operator) is the fastest, followed by methods using itertools (Method 2). The sum method (Method 3) starts well, but as the size of the list increases, its performance deteriorates significantly.
On the other hand, Numpy Methods (see Method 5) are not the fastest, but they have a linear increase in runtime. I suspect that for a huge input list, NumPy will be the best (I didn’t test this).
Conclusion
This guide discussed different methods of converting a 2D Python list into a string. We also tested the runtime speed for each method and found that Method 4 (Using functools and operator methods) is the fastest, followed by the methods using itertools (see Method 2).
The sum function discussed in Method 3 does well for a small input list, but it gets slow so fast as the input size grows.