Iterate a tuple with dict inside - python

Having trouble iterating over tuples such as this:
t = ('a','b',{'c':'d'})
for a,b,c in t:
print(a,b,c) # ValueError: not enough values to unpack (expected 3, got 1)
for a,b,*c in t:
print(a,b,c) # ValueError: not enough values to unpack (expected 2, got 1)
for a,b,**c in t:
print (a,b,c) # Syntax error (can't do **c)
Anyone know how I can preserve the dictionary value? I would like to see a='a', b='b', and c={'c':'d'}

You'd need to put t inside some other iterable container:
for a, b, c in [t]:
print(a, b, c)
The problem with your attempts is that each on is iterating over a single element from t and trying to unpack that. e.g. the first turn of the loop is trying to unpack 'a' into three places (a, b and c).
Obviously, it's also probably better to just unpack directly (no loop required):
a, b, c = t
print(a, b, c)

Why are you iterating at all when it's a single tuple? Just unpack the single tuple, if that's what you need to do:
a, b, c = t
print(a, b, c)
Or if it's just printing you want to do unpack in the call itself:
print(*t)

Try this:
for a,b,c in [t]:
print(a,b,c)
Putting t inside a list will allow you to unpack it.

You can use tuple unpacking with multiple assignment:
a, b, c = t
print(a, b, c)

try this
for x in t:
print(x)
x will take all the values in t iteratively, so 'a', then 'b' and finally {'c':'d'}.
And to print exactly a = 'a' etc you can do:
for param, val in zip(["a","b","c"], t):
print(param,"=",val)

Related

How to combine list and individual elements into one tuple in python?

I have a few variables in python3:
a = 1
b = [2,3,4]
c = 5
I want to get a tuple which is from above variables, like: (1,2,3,4,5)
what is the easiest way to do that in python3?
Creating a tuple in Python is as simple as putting the stuff you need in a tuple in parentheses:
my_tuple = (1, 2, 3)
a = 1
b = 2
c = 3
another_tuple = (a, b, c) # also works with variables, or anything else with a value
And if what you want in the tuple is in something else that can be unpacked, like a list or a tuple itself, you can use the unpacking operator * to unpack it into the new tuple:
a = 1
b = [2,3,4]
c = 5
my_tuple = (a, *b, c)
Not your question, but note that you can also get stuff from a tuple without using the * operator, as it's implied in an assignment statement:
x, _, z = my_tuple # continued from before
In this example, what was in a (1) is now also in x and what was in c also in z. What was in b and in the second position of the tuple gets discards (that's what the underscore _ here means, "don't care".)
You use the unpack operator in cases where you explicitly need to unpack and you're constructing some new variable, or need the elements of the tuple separately where they could also be used as a tuple. For example, when calling a function:
a_tuple = ('Hi there', 'John')
def greeting(phrase='Hello', name='world'):
print(f'{phrase}, {name}!')
greeting(*a_tuple)
In this example, calling greeting as greeting(a_tuple) would give you the very nasty result of ('Hi there', 'John'), world!, clearly not what you want, but you can still use the tuple with the unpack operator.
And the other obvious example is one like the one solving OP's question.
Simply create a new tuple as shown below.
newTuple=(a, *b, c)
Note: *b unpacks list b into variables and add each variable to indexes of newTuple
One of the ways is shown below
from functools import reduce
import operator
# create a bunch of lists, reduce them to one list and finally convert to tuple
result = tuple(reduce(operator.add, ([a], b, [c])))
print(result)
This is the most pythonic solution:
a = 1
b = [2,3,4]
c = 5
res = a,*b,c
# output: (1,2,3,4,5)
Note: To create the new tuple, round brackets are not necessary in Python3

Cleanly assign list values to multiple variables when there may not be enough values to unpack

For example, if I want to assign a, b, c from l = [1,2,3,4,5], I can do
a, b, c = l[:3]
but what if l is only [1,2] (or [1] or []) ?
Is there a way to automatically set the rest of the variables to None or '' or 0 or some other default value?
I thought about extending the list with default values before assigning to match the number of variables, but just wondering if there's a better way.
In general, to unpack N elements into N separate variables from a list of size M where M <= N, then you can pad your list slice upto N and slice again:
l = [1,]
a, b, c = (l[:3] + [None]*3)[:3]
a, b, c
# 1, None, None
If you fancy a clean generator-based approach, this will also work:
from itertools import islice, cycle, chain
def pad(seq, filler=None):
yield from chain(seq, cycle([filler]))
a, b, c = islice(pad([1, ]), 3)
a, b, c
# 1, None, None

How to combine tuples from two generators in python

I want to use two generators in a single for loop. Something like:
for a,b,c,d,e,f in f1(arg),f2(arg):
print a,b,c,d,e,f
Where a,b,c,d and e come from f1 and f comes from f2. I need to use the yield operator because of space constraints.
The above code however doesn't work. Due to some reason it keeps on taking values (for all six variables) from f1 until it is exhausted and then starts taking values from f2.
Please let me know if this is possible and if not is there any workaround. Thank you in advance.
You can use zip (itertools.izip if you're using Python 2) and sequence unpacking:
def f1(arg):
for i in range(10):
yield 1, 2, 3, 4, 5
def f2(arg):
for i in range(10):
yield 6
arg = 1
for (a, b, c, d, e), f in zip(f1(arg), f2(arg)):
print(a, b, c, d, e, f)

What is an elegant way to "change" an element of a tuple? [duplicate]

This question already has answers here:
How to change values in a tuple?
(17 answers)
Closed 8 years ago.
This is extremely likely to be a duplicate of something, but my serach foo is failing me.
It is known that tuples are immutable, so you can't really change them. Sometimes, however, it comes in handy to do something to the effect of changing, say, (1, 2, "three") to (1, 2, 3), perhaps in a similar vein to the Haskell record update syntax. You wouldn't actually change the original tuple, but you'd get a new one that differs in just one (or more) elements.
A way to go about doing this would be:
elements = list(old_tuple)
elements[-1] = do_things_to(elements[-1])
new_tuple = tuple(elements)
I feel that changing a tuple to a list however kind of defeats the purpose of using the tuple type for old_tuple to begin with: if you were using a list instead, you wouldn't have had to build a throw-away list copy of the tuple in memory per operation.
If you were to change, say, just the 3rd element of a tuple, you could also do this:
def update_third_element(a, b, c, *others):
c = do_things_to(c)
return tuple(a, b, c, *others)
new_tuple = update_third_element(*old_tuple)
This would resist changes in the number of elements in the tuple better than the naive approach:
a, b, c, d, e, f, g, h, i, j = old_tuple
c = do_things_to(c)
new_tuple = (a, b, c, d, e, f, g, h, j, j) # whoops
...but it doesn't work if what you wanted to change was the last, or the n-th to last element. It also creates a throw away list (others). It also forces you to name all elements up to the n-th.
Is there a better way?
I would use collections.namedtuple instead:
>>> from collections import namedtuple
>>> class Foo(namedtuple("Foo", ["a", "b", "c"])):
pass
>>> f = Foo(1, 2, 3) # or Foo(a=1, b=2, c=3)
>>> f._replace(a = 5)
Foo(a=5, b=2, c=3)
namedtuples also support indexing so you can use them in place of plain tuples.
If you must use a plain tuple, just use a helper function:
>>> def updated(tpl, i, val):
return tpl[:i] + (val,) + tpl[i + 1:]
>>> tpl = (1, 2, 3)
>>> updated(tpl, 1, 5)
(1, 5, 3)

Unpack error with tuple of tuples?

I want to iterate over the elements ((a,b),(x,y)) so I tried:
def method(tuple):
((a,b),(x,y))= tuple
for element in tuple:
.....
But then I read another stackoverflow page which suggested something like this:
def method(tuple):
((a,b),(x,y))= tuple
for element in tuple[0:4]:
.....
Both resulted in the error: ValueError: need more than 1 value to unpack.
Is this action not allowed in python, or do I just have a syntax problem?
I have checked the python docs as well.
Thanks for any advice.
Edit
map = ((1,0),(3,2))
def count(map):
((a,b),(x,y))= tuple
inc=0
for element in tuple:
inc+=1
If you have a tuple of tuples, of the form ((a, b), (x, y)), you can iterate over its elements:
def method(tuples):
for tup in tuples:
for e in tup:
print e
If you want to have 4 variables, you can use them separately:
def method(tuples):
(a, b), (x, y) = tuples
print a, b, x, y
Note:
Don't use Python built-in names as name of variables. In other words, don't use tupleas a name of a variable because it's a type in Python. Use something else, like tuples, my_tuple, ...

Categories