3

Assume the following list: foo = [(1, 2, 3, 4), (5, 6, 7, 8)]

Is there a way to iterate over the list and unpack the first two elements of the inner tuple only?

This is a usual pattern: {a: b for a, b, _, _ in foo}, but this breaks if foo is modified (program change) and the tuple now contains 5 elements instead of 4 (the the list comprehension would need to be modified accordingly). I really like to name the elements instead of calling {f[0]: f[1] for f in foo}, so ideally, there would be some sort of "absorb all not unpacked variable", so one could call {a: b for a, b, absorb_rest in foo}. If that's possible, it wouldn't matter how many elements are contained in the tuple (as long as there are at least 2).

orange
  • 7,755
  • 14
  • 75
  • 139
  • what do you want your result to look like? – Ma0 Jun 14 '19 at 09:53
  • In the example above: `{1: 2, 5: 6}`, but that's just an example. I'd like to extract the first two elements from the tuples, so for instance, if I were to look for `[a + b for a, b, _, _ in foo]`, I would expect `[3, 11]`. – orange Jun 14 '19 at 09:55

4 Answers4

5

You can use extended iterable unpacking, where you extract the first two elements of the tuple, and ignore the rest of the elements. Note that this only works for python3

{a:b for a, b, *c in foo}                                                                                                                                                             
Devesh Kumar Singh
  • 20,259
  • 5
  • 21
  • 40
5

You can use extended iterable unpacking, keeping in this way the first two values from the iterable and ignoring the rest:

{a: b for a, b, *_ in foo}
# {1: 2, 5: 6}
yatu
  • 86,083
  • 12
  • 84
  • 139
  • `a` and `b` are just examples. It's just making the code more readable when the elements are named (`a` and `b` are proxies for readable names ;-)). – orange Jun 14 '19 at 10:27
  • Are you saying that the variable `_` won't contain any value (or even exist) after completing the list comprehension? That would be unusual... – orange Jun 14 '19 at 10:31
  • No, I am not interested in the remaining values (I was just confused by your comment "Otherwise they will be unnecessarily kept in memory"). My understanding is that `*_` and `*c` are equivalent (both are variables) and the last assignment to the variable (last iteration) will be available after the list comprehension. – orange Jun 14 '19 at 10:37
  • 1
    @yatu I don't think that's true. `_` is a convention here, I don't believe it is never allocated memory in any circumstance. `a, _ = [1, 2]; print(_)` or (in poor practice) `a = [print(a, _) for a, _ in [[1, 2], [3, 4]]]` – roganjosh Jun 14 '19 at 10:38
  • @roganjosh I agree with that. That's where my confusion stems from. `_` or `c` are equivalent and just variable names (`_` is used more often as it's a convention). – orange Jun 14 '19 at 10:39
  • 1
    Underscore has other uses beyond the convention here, such as [this](https://stackoverflow.com/questions/1538832/is-the-single-underscore-a-built-in-variable-in-python) – roganjosh Jun 14 '19 at 10:41
  • I wasn't ;-) Thanks for that comment @roganjosh. – orange Jun 14 '19 at 10:44
  • Ahh just learnt something new then :)) will clear up the comments @roganjosh devesh – yatu Jun 14 '19 at 10:44
  • Yes of course @roganjosh agreed :) besides it can indeed lead to some confusion being simply a convention (as in my own case) – yatu Jun 14 '19 at 10:56
3

Try this :

dict_ = {a:b for a,b, *_ in foo}

Output :

{1: 2, 5: 6}

If foo is changed to [(1, 2, 3, 4,9,0), (5, 6, 7, 8, 11, 16)] by program later, dict_ still remains : {1: 2, 5: 6}

Arkistarvh Kltzuonstev
  • 6,824
  • 7
  • 26
  • 56
0

use lambda

foo = [(1, 2, 3, 4), (5, 6, 7, 8)]
output = list(map(lambda x:{x[0]:x[1]}, foo))
print(output)

output

[{1: 2}, {5: 6}]
sahasrara62
  • 10,069
  • 3
  • 29
  • 44