28

I have the following element of a list, and the list is 100 elements long.

[(50, (2.7387451803816479e-13, 219))]

How do I convert each element to look like this?

[(50, 2.7387451803816479e-13, 219)]
olliepower
  • 1,269
  • 2
  • 11
  • 17
  • The question is not well specified. Does every element have the same structure? What kind of structures need to be handled? Also: is the question really about how to convert a single element of the list, or about how to repeat that process for each element? If it's about both, that is two questions - "repeat a process for each element of a list" doesn't generally depend on what the process is. – Karl Knechtel Sep 10 '22 at 08:59

7 Answers7

20
[(a, b, c) for a, (b, c) in l]

Tuple packing and unpacking solves the problem.

Bonifacio2
  • 3,405
  • 6
  • 34
  • 54
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • 4
    How exactly does the link in the answer help with this problem? – GreenAsJade Oct 10 '14 at 10:21
  • 9
    That works when you know the tuple structure, but sometimes the reason it needs to be flattened is because the structure is unknown. e.g. np.where can return a tuple with a single value or a tuple with a list of values, in which case, the tuple needs to be accessed differently. How can this situation be handled? – DanGoodrick Aug 20 '15 at 20:49
  • @DanGoodrick: np.where doesn't do that. The tuple never contains a list; it's always a tuple of numpy arrays, and except for a weird edge case with 0-dimensional arrays, the number of arrays is always equal to the dimension of the input array. There is no need to access the tuple differently in different cases, and flattening it doesn't make much sense. – user2357112 Aug 21 '15 at 01:57
14

New in Python 3.5 with the additional tuple unpacking introduced in PEP 448, you can use starred expressions in tuple literals such that you can use

>>> l = [(50, (2.7387451803816479e-13, 219)), (40, (3.4587451803816479e-13, 220))]
>>> [(a, *rest) for a, rest in l]
[(50, 2.738745180381648e-13, 219), (40, 3.458745180381648e-13, 220)]

This could be useful if you had a nested tuple used for record-keeping with many elements that you wanted to flatten.

miradulo
  • 28,857
  • 6
  • 80
  • 93
6

Your could use the following function and apply it in a loop to every element in the list.

def flatten(data):
    if isinstance(data, tuple):
        if len(data) == 0:
            return ()
        else:
            return flatten(data[0]) + flatten(data[1:])
    else:
        return (data,)

How it works:

  • First it will be checked if type is tuple, if not, it "tuples" the argument
  • Second line returns an empty tuple, if tuple is empty
  • Third line gets out the first element and calls the function recursively

The nice thing in this solution is:

  • It is not necessary to know the structure of the given tuple
  • The tuple can be nested arbitrarily deep
  • Works in Python 2.2+ (and probably earlier)

The code is slightly adapted from following source:
https://mail.python.org/pipermail/tutor/2001-April/005025.html

Hope it helps someone :)

Jim Pivarski
  • 5,568
  • 2
  • 35
  • 47
sagacity
  • 341
  • 3
  • 7
3

An improvement from @sagacity answer, this will rerun a generator that flattens the tuple using a recursive and yield.

def flatten(data):
    if isinstance(data, tuple):
        for x in data:
            yield from flatten(x)
    else:
        yield data

To make it into list or tuple, use list() or tuple().

list(flatten(nested_tuple))
tuple(flatten(nested_tuple))

If it needs to work in Python 2, replace the yield from with another loop:

def flatten(data):
    if isinstance(data, tuple):
        for x in data:
            for y in flatten(x):
                yield y
    else:
        yield data
Muhammad Yasirroni
  • 1,512
  • 12
  • 22
1

You can get the result in this way

>> example =  [(50, (2.7387451803816479e-13, 219))]
>>> [tuple(x[:1]) + (x[1]) for x in example] 
[(50, 2.738745180381648e-13, 219)]
Sachin Sukumaran
  • 707
  • 2
  • 9
  • 25
1

A Python 2.7 compatible way to do what Mitch suggests for Python 3.5.

>>> example =  [(50, (2.7387451803816479e-13, 219)),
            (100, (3.7387451803816479e-13, 218))]
>>> [(lambda *x: x)(k, *r) for k, r in example]
[(50, 2.738745180381648e-13, 219), (100, 3.7387451803816477e-13, 218)]

The advantage of this method is that you do not have to find a variable name for each value of the internal tuple to flatten like in the accepted answer. If there are two or three items, that's not really an issue, but imagine there are tenths values or more...

kriss
  • 23,497
  • 17
  • 97
  • 116
0

This code works for nested tuples:

def flatten(args):
    try:
        iter(args)
        final = []
        for arg in args:
            final += flatten(arg)
        return tuple(final)
    except TypeError:
        return (args, )

flatten([1, 2, 3, 4])  # (1, 2, 3, 4)
flatten([1, [2, 3], 4])  # (1, 2, 3, 4)
flatten([1, [2, [3]], [[4]]])  # (1, 2, 3, 4)
Carlos Adir
  • 452
  • 3
  • 9