1

I'm working with lists of single tuples that looks like this:

data = [[('jog',), ('Jim',), ('jell',), ('jig',)], [('jabs',), ('jilt',), ('job',), ('jet',)]]

Notice that the list contains two elements: two lists containing 4 tuples. Basically, I'm just trying to remove each tuple and make it look like this:

data = [['jog','Jim','jell','jig'], ['jabs','jilt','job','jet']]

I think this can probably be done with list comprehension, but I've tried for hours and can't come up with the magic formula. Can anyone help with this?

Timur Shtatland
  • 12,024
  • 2
  • 30
  • 47
thedude
  • 597
  • 5
  • 5

3 Answers3

2

The listcomp "magic formula" you're looking for is best done with a nested listcomp using unpacking in the innermost listcomp:

data = [[x for [x] in sublist] for sublist in data]

The [x] there triggers the unpacking of the single element tuple in the most efficient manner possible (while also verifying it is in fact exactly one element per tuple, no more, no less). Otherwise it's a largely no-op nested listcomp.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • How is using `[x for [x] in sublist]` different than using `[x[0] for x in sublist]`? – user107511 May 25 '22 at 16:17
  • 1
    @user107511: Two improvements: 1) It's faster (indexing takes ~20% longer; indexing is weirdly slow in CPython; that may improve with 3.11, which adds self-optimizing bytecode for integer indexing of `list`/`tuple` IIRC). 2) It verifies the OP's assumption that it's a `list` of `list` of one-`tuple`s (technically, any iterable of iterables of one-element iterables would work; close enough). If any of those nested `tuple`s are actually 2+ elements (or empty, but indexing would handle that), this will die with an exception, where indexing would just silently discard the elements above index 0. – ShadowRanger May 25 '22 at 16:59
  • @user107511 If the inner list has small fixed size as well, we can even [take this further](https://ideone.com/hTBqhw) (see the benchmark results at the bottom). – Kelly Bundy May 25 '22 at 17:10
1

Use list comprehension like so:

data = [[('jog',), ('Jim',), ('jell',), ('jig',)], [('jabs',), ('jilt',), ('job',), ('jet',)]]
data = [[tup[0] for tup in lst] for lst in data]
print(data)
# [['jog', 'Jim', 'jell', 'jig'], ['jabs', 'jilt', 'job', 'jet']]
Timur Shtatland
  • 12,024
  • 2
  • 30
  • 47
  • 1
    Minor weakness here: It will silently discard data if it turns out an inner `tuple`s *isn't* a singleton. It's also slightly slower than unpacking (it's a minor loss if this isn't the hottest code path, only a 20% increased runtime). – ShadowRanger May 25 '22 at 16:01
0

If you want to flatten your tuples in a list, you can use itertools.chain:

import itertools

data = [[('jog',), ('Jim',), ('jell',), ('jig',)], [('jabs',), ('jilt',), ('job',), ('jet',)]]

result = [list(itertools.chain(*d)) for d in data]

# result = [['jog', 'Jim', 'jell', 'jig'], ['jabs', 'jilt', 'job', 'jet']]
user107511
  • 772
  • 3
  • 23