Assigning Values to Tuple in for Loop

How to create tuple with a loop in python

Use an extra comma in your tuples, and just join:

a = ((1,1,1),)
for i in range(2,10):
a = a + ((i,i,i),)

Edit: Adapting juanpa.arrivillaga's comment, if you want to stick with a loop, this is the right solution:

a = [(1,1,1)]
for i in range (2,10):
a.append((i,i,i))
a = tuple(a)

Assigning values to tuple in for loop

There's no official API for doing this, but IIRC, tuples of homogeneous element types are guaranteed to have a contiguous memory layout. You take advantage of this by using UnsafeBufferPointer to read/write to the tuple.

Usually this requires you to manually hard-code the tuple's element count, but I wrote some helper functions that can do this for you. There's two variants, a mutable one, which lets you obtain an UnsafeBufferPointer, which you can read (e.g. to create an Array), and a mutable one, which gives you a UnsafeMutableBufferPointer, through which you can assign elements.

enum Tuple {
static func withUnsafeBufferPointer<Tuple, TupleElement, Result>(
to value: Tuple,
element: TupleElement.Type,
_ body: (UnsafeBufferPointer<TupleElement>) throws -> Result
) rethrows -> Result {
try withUnsafePointer(to: value) { tuplePtr in
let count = MemoryLayout<Tuple>.size / MemoryLayout<TupleElement>.size

return try tuplePtr.withMemoryRebound(
to: TupleElement.self,
capacity: count
) { elementPtr in
try body(UnsafeBufferPointer(start: elementPtr, count: count))
}

}
}

static func withUnsafeMutableBufferPointer<Tuple, TupleElement, Result>(
to value: inout Tuple,
element: TupleElement.Type,
_ body: (UnsafeMutableBufferPointer<TupleElement>) throws -> Result
) rethrows -> Result {
try withUnsafeMutablePointer(to: &value) { tuplePtr in
let count = MemoryLayout<Tuple>.size / MemoryLayout<TupleElement>.size

return try tuplePtr.withMemoryRebound(
to: TupleElement.self,
capacity: count
) { elementPtr in
try body(UnsafeMutableBufferPointer(start: elementPtr, count: count))
}

}
}
}

var destinationTouple: (Int, Int, Int, Int) = (0, 0, 0, 0) // => (0, 0, 0, 0)
var sourceArray = Array(1...4)

print("before:", destinationTouple)

Tuple.withUnsafeMutableBufferPointer(to: &destinationTouple, element: Int.self) { (destBuffer: UnsafeMutableBufferPointer<Int>) -> Void in
sourceArray.withUnsafeMutableBufferPointer { sourceBuffer in
// buffer[...] = 1...
destBuffer[destBuffer.indices] = sourceBuffer[destBuffer.indices]
return ()
}
}

print("after:", destinationTouple) // => (1, 2, 3, 4)

Tuples in For Loops - Python

Tuples are immutable objects, that is, you cannot change the elements of the tuple once it is created, if you do want to change them it would be better to use a list.

a = [3, 2]
for i in a:
i -= 1
print(a)

Which gives an output:

[3, 2]

Why didn't it work, even though lists are mutable? And also, why doesn't your original code produce some kind of error, if tuples are really immutable? Well, this becomes more obvious if you write your for each style loop as a simple for:

for index in range(len(a)):
i = a[index]
i -= 1
print(a)

This code is just a more verbose version of your original example, but now the problem is clear - the code never actually changes the elements of the original list. Instead, each iteration of the for loop creates a new variable, i, which takes its value from the correspondinglist element. i -= 1 changes i, not a[index].

Incidentally, that is why there is no error in your original code, even though tuples are supposed to be immutable - the code simply doesn't try to mutate the original tuple at all.

A working example with a list would be something like:

a = [3, 2]
for index in range(len(a)):
a[index] -= 1

print(a)

which can be made more concise in the end by writing:

a = [3, 2]
a = [i - 1 for i in a]
print(a)

As an aside, if you really must take tuples as input and produce tuples as output, you can convert between tuples and lists using the list and tuple functions. This is also why you shouldn't use tuple as your variable name! Doing so will mean that you can't use that tuple function in the same scope as your tuple variable, making things very difficult and potentially confusing for you.

loop through a python list of tuples and change a value

This does it:

a=[(1,'Rach', 'Mell', '5.11', '160'),(2, 'steve', 'Rob', '6.1', '200'), (1,'Rach', 'Mell', '5.11', '160')]

for i,e in enumerate(a):
if e[0]==2:
temp=list(a[i])
temp[2]='Roberto'
a[i]=tuple(temp)

print a

Prints:

[(1, 'Rach', 'Mell', '5.11', '160'), (2, 'steve', 'Roberto', '6.1', '200'), (1, 'Rach', 'Mell', '5.11', '160')]

If you want a list comprehension, this:

>>> [t if t[0]!=2 else (t[0],t[1],'Roberto',t[3],t[4]) for t in a]
[(1, 'Rach', 'Mell', '5.11', '160'), (2, 'steve', 'Roberto', '6.1', '200'), (1, 'Rach', 'Mell', '5.11', '160')]

Creating a tuple using a for loop.

Let's walk through your code step by step so that you get an idea of the errors you are making, then let's look at a correct solution. Finally, let's look at the pythonic solution that might annoy your teacher.

The line

index = 0

is fine, because you want to start counting the indices at zero. The line

element = [(5,3,2,6)]

makes no sense, because your function should work for any given list, not just for your test case. So let's delete it.
You initialize your result list with

li = []

which would be fine if you would not re-use the name of the given input list li which is discarding the argument given to the function. Use

result = []

instead. Next your are looping over your now empty list li with

for index in li:

and since li is empty at this point, the loop body will never execute. Naming your loop variable index is confusing because you are looping over the elements of a list with that syntax, not over the indices.

li.append((element, index))

Inside your for loop is just wrong because you are never increasing index and element is a list, not a single element from your input list.

Here's a commented version of a working solution:

def list_ele_idx(li):
index = 0 # start counting at index 0
result = [] # initialize an empty result list
for item in li: # loop over the items of the input list
result.append((item, index)) # append a tuple of the current item and the current index to the result
index += 1 # increment the index
return result # return the result list when the loop is finished

Using enumerate(li) would give you a simpler solution, but I don't think that's in the spirit of the exercise. Anyway, the short solution is:

def list_ele_idx(li):
return [(y,x) for x,y in enumerate(li)]

How to fill a tuple with a for loop

Tuples are immutable, so you can't modify them after creating them. If you need to modify the data structure, you'll need to use a list.

However, instead of using a for loop, you can pass a generator expression to tuple() and make the tuple all at once. This will give you both the tuple you want and a way to make it cleanly.

import collections

Experiment = collections.namedtuple('Experiment', ['parameter', ])

nsize = 3

parameters = {}
for n in range(0, nsize):
parameters[n] = n + 1

expirements = tuple(Experiment(parameter = parameters[n]) for n in range(nsize))
# (Experiment(parameter=1), Experiment(parameter=2), Experiment(parameter=3))

How are tuples unpacked in for loops?

You could google "tuple unpacking". This can be used in various places in Python. The simplest is in assignment:

>>> x = (1,2)
>>> a, b = x
>>> a
1
>>> b
2

In a for-loop it works similarly. If each element of the iterable is a tuple, then you can specify two variables, and each element in the loop will be unpacked to the two.

>>> x = [(1,2), (3,4), (5,6)]
>>> for item in x:
... print "A tuple", item
A tuple (1, 2)
A tuple (3, 4)
A tuple (5, 6)
>>> for a, b in x:
... print "First", a, "then", b
First 1 then 2
First 3 then 4
First 5 then 6

The enumerate function creates an iterable of tuples, so it can be used this way.

Looping through to create a tuple

If I understand correctly, this is pretty simple with a comprehension.

emails = [
(u'Subject', u'Message.', u'from@example.com', [address])
for name, address in recipients
]
send_mass_mail(emails)

Note that we leverage Python's ability to unpack tuples into a set of named variables. For each element of recipients, we assign its zeroth element to name and its first element to address. So in the first iteration, name is u'John' and address is u'john@example.com'.

If you need to vary the 'Message.' based on the name, you can use string formatting or any other formatting/templating mechanism of your choice to generate the message:

emails = [
(u'Subject', u'Dear {}, Message.'.format(name), u'from@example.com', [address])
for name, address in recipients
]

Since the above are list comprehensions, they result in emails being a list. If you really need this to be a tuple instead of a list, that's easy, too:

emails = tuple(
(u'Subject', u'Message.', u'from@example.com', [address])
for name, address in recipients
)

For this one, we're actually passing a generator object into the tuple constructor. This has the performance benefits of using a generator without the overhead of creating an intermediate list. You can do that pretty much anywhere in Python where an iterable argument is accepted.



Related Topics



Leave a reply



Submit