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 list
s are mutable? And also, why doesn't your original code produce some kind of error, if tuple
s 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 tuple
s 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 tuple
s as input and produce tuple
s as output, you can convert between tuple
s and list
s 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 tuple
s 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
How to Reconnect Akplayer and Akmixer After Audiokit.Stop()
How to Use Gpx File for UI Tests Only
Parse Codable Classes and Avoid Repetition
Invalid Update: Invalid Number of Rows in Section 1
Secidentity + Force Cast Violation: Force Casts Should Be Avoided. (Force_Cast)
Root Class of All Classes in Swift
Idiomatic Way to Test Swift Optionals
Could Not Find Member <Method Name> for Struct Type in Swift
Swift: Tvos Ibaction for UIcontrol in Collection View Cell Never Gets Called
Arkit/Scenekit on iOS 14 Throws New Warning (Metal)
Exc Bad Access While Creating a New Characterset
Applescript Email Attachment Not Working in Handler
Why Does User Defaults Publisher Trigger Multiple Times
Flattened Objects in JSON File to Nested Object Structure in Swift
Swift Equivalent of Objective-C for Flutter Native Ads
How to Set a Known Position and Orientation as a Starting Point of Arkit