19

I am writing a small script to help out with Japanese kana memorisation. How would I combine the following lists into one? I tried as follows.

a = ["a",   "i",   "u",   "e",   "o"]
k = ["ka",  "ki",  "ku",  "ke",  "ko"]
g = ["ga",  "gi",  "gu",  "ge",  "go"]
s = ["sa",  "shi", "su",  "se",  "so"]
z = ["za",  "ji",  "zu",  "ze",  "zo"]
t = ["ta",  "chi", "tsu", "te",  "to"]
d = ["da",         "du",  "de",  "do"]
n = ["na",  "ni",  "nu",  "ne",  "no"]
h = ["ha",  "hi",  "hu",  "he",  "ho"]
b = ["ba",  "bi",  "bu",  "be",  "bo"]
p = ["pa",  "pi",  "pu",  "pe",  "po"]
m = ["ma",  "mi",  "mu",  "me",  "mo"]
y = ["ya",         "yu",         "yo"]
n = ["n"]

kana = [a, k, g, s, z, t, d, n, h, b, p, m, y, n]

print kana
juliomalegria
  • 24,229
  • 14
  • 73
  • 89
abkai
  • 591
  • 2
  • 6
  • 18
  • Thanks, I did perform a search for that but couldn't find anything useful. These answers have all been helpful, thank you to everyone! :) – abkai May 05 '12 at 05:52

8 Answers8

22

One way:

kana = a + k + g + s + z + t + d + n + h + b + p + m + y + n
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
18

The question is effectively asking how do you flatten that list of lists, which is answered here: join list of lists in python.

You could print out everything by doing something like:

import itertools
print list(itertools.chain(*kana))
Community
  • 1
  • 1
Jack Kelly
  • 18,264
  • 2
  • 56
  • 81
  • 3
    or `chain.from_iterable(kana)` – John La Rooy May 03 '12 at 03:10
  • 2
    In my opinion, the itertools solution is definitely suitable for those who are used to itertools and who use the module in other code. Otherwise, it is less self-explanatory than using the methods of the basic types. It is also slower -- see the timeit in my answer. – pepr May 03 '12 at 11:25
9

My +1 for the explicit for loop with .extend()

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
...
Readability counts.
...
In the face of ambiguity, refuse the temptation to guess.
...

When measured, the plain for loop is faster than the side-effect by the list comprehension.

import itertools
import timeit

def flattenListOfLists(lst):
    result = []
    for sublist in lst:
        result.extend(sublist)
    return result

def flattenListOfLists2(lst):
    result = []
    [result.extend(sublist) for sublist in lst]  # uggly side effect ;)
    return result

def flattenIterTools(lst):
    return list(itertools.chain(*lst))


a = ["a",   "i",   "u",   "e",   "o"]
k = ["ka",  "ki",  "ku",  "ke",  "ko"]
g = ["ga",  "gi",  "gu",  "ge",  "go"]
s = ["sa",  "shi", "su",  "se",  "so"]
z = ["za",  "ji",  "zu",  "ze",  "zo"]
t = ["ta",  "chi", "tsu", "te",  "to"]
d = ["da",         "du",  "de",  "do"]
n = ["na",  "ni",  "nu",  "ne",  "no"]
h = ["ha",  "hi",  "hu",  "he",  "ho"]
b = ["ba",  "bi",  "bu",  "be",  "bo"]
p = ["pa",  "pi",  "pu",  "pe",  "po"]
m = ["ma",  "mi",  "mu",  "me",  "mo"]
y = ["ya",         "yu",         "yo"]
n = ["n"]

kana = [a, k, g, s, z, t, d, n, h, b, p, m, y, n]

t = timeit.timeit('lst = flattenListOfLists(kana)', 'from __main__ import kana, flattenListOfLists', number=100000)
print 'for loop:', t

t = timeit.timeit('lst = flattenListOfLists2(kana)', 'from __main__ import kana, flattenListOfLists2', number=100000)
print 'list comprehension side effect:', t

t = timeit.timeit('lst = flattenIterTools(kana)', 'from __main__ import kana, flattenIterTools\nimport itertools', number=100000)
print 'itertools:', t

It prints on my console:

for loop: 0.389831948464
list comprehension side effect: 0.468136159616
itertools: 0.620626692887

Anyway, the time is for repeating the same 100 thousands times. The readability counts is my argument.

pepr
  • 20,112
  • 15
  • 76
  • 139
5
kana = sum([a, k, g, s, z, t, d, n, h, b, p, m, y, n], [])
spinlok
  • 3,561
  • 18
  • 27
  • 2
    Using `sum()` with lists has quadratic performance. It will created a brand new list each time it adds another list – John La Rooy May 03 '12 at 03:09
  • Isn't that the case with the '+' operator too? – spinlok May 03 '12 at 03:11
  • 1
    @spinlok yes, `+` and `sum` are equivalently bad for this. The best way is using `itertools.chain`, per @JackKelly and @gnibbler , which doesn't build any intermediate lists. – lvc May 03 '12 at 04:01
2

One should also be aware of one very important fact, that the flattened list shares the original objects with the original list of lists. This is not a problem in this case, as the objects are immutable strings. If the objects were mutable, changing them in one structure would change the element value observable via the second structure.

To summarize, one have to know a bit more about Python internals. Sometimes we want to make a copy of the original sublists, like that:

...
result = []
for sublist in lst:
    result.extend(sublist[:])     # notice the [:] here
...
pepr
  • 20,112
  • 15
  • 76
  • 139
1

The following is a list comprehension with so_on being used as a short-cut just in the example to represent the actual remaining lists that you want to combine.

The long way:

>>> all_list = [e for l in [a, k, so_on] for e in l]
Saeed
  • 3,294
  • 5
  • 35
  • 52
Vidul
  • 10,128
  • 2
  • 18
  • 20
1
kana = [a, k, g, s, z, t, d, n, h, b, p, m, y, n]
combined_list=[]
for x in kana:
    combined_list.extend(x) 
print(combined_list)

['a', 'i', 'u', 'e', 'o', 'ka', 'ki', 'ku', 'ke', 'ko', 'ga', 'gi', 'gu', 'ge', 'go', 'sa', 'shi', 'su', 'se', 'so', 'za', 'ji', 'zu', 'ze', 'zo', 'ta', 'chi', 'tsu', 'te', 'to', 'da', 'du', 'de', 'do', 'n', 'ha', 'hi', 'hu', 'he', 'ho', 'ba', 'bi', 'bu', 'be', 'bo', 'pa', 'pi', 'pu', 'pe', 'po', 'ma', 'mi', 'mu', 'me', 'mo', 'ya', 'yu', 'yo', 'n']
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • 1
    Using a list comprehension for a side-effect is generally considered unpythonic – John La Rooy May 03 '12 at 03:07
  • @gnibbler you're right, but I just used it here because list comprehensions are fast. – Ashwini Chaudhary May 03 '12 at 03:30
  • 1
    Really? Did you time the LC vs a `for` loop? – John La Rooy May 03 '12 at 04:45
  • 2
    `for x in kana:combined_list.extend(x)` is 20% faster than the LC on my computer – John La Rooy May 03 '12 at 11:01
  • @Ashwini Chaudhary: "In the face of ambiguity, refuse the temptation to guess." ;) I agree with gnibbler, but I think that this is a valuable example to learn from. I am not going to up-vote, but I am not going to donw-vote either. **The side effects should be avoided (if possible) not only in Python.** – pepr May 03 '12 at 11:31
  • @gnibbler thanks, I really didn't knew that LCs when used as a side-effect are slower than a for-loops, Solution Edited. – Ashwini Chaudhary May 03 '12 at 15:42
1

Other way with lambda

kana = [a, k, g, s, z, t, d, n, h, b, p, m, y, n]

reduce(lambda x,y: x+y,kana)
Mirage
  • 30,868
  • 62
  • 166
  • 261