Whether Rect.midleft (or midright, etc.) is a tuple - python

I've been working on a space shooting game in which the particles attached to the ship's engine resemble the fire that comes out of the engine. I used ship_rect.midleft to give the information on the position that the particles were generated, yet the command prompt responded to me:
ship_particle [0][0] += ship_particle [1]
TypeError: can only concatenate tuple (not "int") to tuple
What should I do with this?
ship_particles = []
while True
......
ship_particles.append([[ship_rect.midleft],-3, random.randint(5,6)])
for ship_particle in ship_particles:
ship_particle [0][0] += ship_particle [1]
ship_particle [2] -= 0.1
pygame.draw.circle(screen,(255,255,255),ship_particle[0],ship_particle[2])
ship_particle_copy = [ship_particle for ship_particle in ship_particles if ship_particle[2]>0]
ship_particles = ship_particle_copy

ship_rect.midleft is a tuple. Actually you are appending a list with 1 tuple. Since you cannot change the elements of a tuple you have to make a list from the tuple. Use the asterisk (*) operator and unpacking the tuple. Just add [*ship_rect.midleft] instead of [ship_rect.midleft]
ship_particles.append([[ship_rect.midleft],-3, random.randint(5,6)])
ship_particles.append([[*ship_rect.midleft], -3, random.randint(5,6)])
Alternatively use the built-in list function:
ship_particles.append([list(ship_rect.midleft), -3, random.randint(5,6)])
Compare
ship_rect = pygame.Rect(10, 10, 20, 20)
print([ship_rect.midleft])
[(10, 20)]
and
ship_rect = pygame.Rect(10, 10, 20, 20)
print([*ship_rect.midleft])
[10, 20]

Related

Double the size of a list of random integers, then sort and print it

Here, I have a list of random integers:
import random
list = [random.randint(0, 30) for x in range(6)]
pass
I want to double the size of this list, sort it, and print it. Here's what I've tried:
def list_doubled(list):
doubled = []
i = 0
while i <= len(list):
for item in list:
doubled.append(list[i])
doubled.append(list[i])
i += 1
print(doubled)
list_doubled(list)
This code is meant to only double the size of the list. When I run the program, I get "IndexError: list index out of range" with emphasis on lines 11 and 16.
In Python you can double a list by just multiplying it by 2.
>>> import random
>>> nums = [random.randint(0, 30) for _ in range(6)]
>>> print(nums)
[5, 30, 28, 11, 19, 17]
>>> print(sorted(nums * 2))
[5, 5, 11, 11, 17, 17, 19, 19, 28, 28, 30, 30]
Creating the list:
import random
numbers = [random.randint(0, 30) for x in range(6)]
Use extend to add the list to itself, in order to double it:
numbers.extend(numbers) # or numbers += numbers
Or add as many random numbers as there are items in the list, if you need the additional numbers to also be random:
numbers.extend(random.randint(0, 30) for _ in range(len(numbers)))
use sort to sort it:
numbers.sort()
Use print to print it:
print(numbers)
Change your <= to < in your while loop line while i <= len(list):. You also might want to look at the comments, they have good advise on additional potential bugs you might encounter.

How to get a list of values from tuples which the second value is the same as first in the next tuple?

I'm having trouble trying to create a list of values from a list of tuples, which link to where the second value is the same as the first value in another tuple, that starts and ends with certain values.
For example:
start = 11
end = 0
list_tups = [(0,1),(0, 2),(0, 3),(261, 0),(8, 15),(118, 32),(11, 8),(15, 118),(32, 261)]
So I want to iterate through those list of tups, starting with the one which is the same as the start value and searching through the tups where it'll end with the end value.
So my desired output would be:
[11, 8, 15, 118, 32, 261, 0]
I understand how to check the values i'm just having trouble with interating through the tuples every time to check if there is a tuple in the list that matches the second value.
You are describing pathfinding in a directed graph.
>>> import networkx as nx
>>> g = nx.DiGraph(list_tups)
>>> nx.shortest_path(g, start, end)
[11, 8, 15, 118, 32, 261, 0]
This doesn't work with end = 0 because there is no 0 at the end, but here it is with 32:
>>> start = 11
>>> end = 32
>>> flattened = [i for t in list_tups for i in t]
>>> flattened[flattened.index(start):flattened.index(end, flattened.index(start))+1]
[11, 8, 15, 118, 32]
You can recursively search the tuples, moving the start value closer and closer. The path will be accumulated as we move back up through the chain You may need to tweak the path a little to get your desired outcome (I believe you'll need to append the first starting value, then reverse it).
def find(start, end, tuples, path):
for t in tuples:
if t[0] == start:
if t[1] == end or find(t[1], end, tuples):
path.append(t[1])
return True
return False

Why can I add tuples, but not subtract? [duplicate]

I am not sure if I can make myself clear but will try.
I have a tuple in python which I go through as follows (see code below). While going through it, I maintain a counter (let's call it 'n') and 'pop' items that meet a certain condition.
Now of course once I pop the first item, the numbering all goes wrong, how can I do what I want to do more elegantly while removing only certain entries of a tuple on the fly?
for x in tupleX:
n=0
if (condition):
tupleX.pop(n)
n=n+1
As DSM mentions, tuple's are immutable, but even for lists, a more elegant solution is to use filter:
tupleX = filter(str.isdigit, tupleX)
or, if condition is not a function, use a comprehension:
tupleX = [x for x in tupleX if x > 5]
if you really need tupleX to be a tuple, use a generator expression and pass that to tuple:
tupleX = tuple(x for x in tupleX if condition)
Yes we can do it.
First convert the tuple into an list, then delete the element in the list after that again convert back into tuple.
Demo:
my_tuple = (10, 20, 30, 40, 50)
# converting the tuple to the list
my_list = list(my_tuple)
print my_list # output: [10, 20, 30, 40, 50]
# Here i wanna delete second element "20"
my_list.pop(1) # output: [10, 30, 40, 50]
# As you aware that pop(1) indicates second position
# Here i wanna remove the element "50"
my_list.remove(50) # output: [10, 30, 40]
# again converting the my_list back to my_tuple
my_tuple = tuple(my_list)
print my_tuple # output: (10, 30, 40)
Thanks
In Python 3 this is no longer an issue, and you really don't want to use list comprehension, coercion, filters, functions or lambdas for something like this.
Just use
popped = unpopped[:-1]
Remember that it's an immutable, so you will have to reassign the value if you want it to change
my_tuple = my_tuple[:-1]
Example
>>> foo= 3,5,2,4,78,2,1
>>> foo
(3, 5, 2, 4, 78, 2, 1)
foo[:-1]
(3, 5, 2, 4, 78, 2)
If you want to have the popped value,,
>>> foo= 3,5,2,4,78,2,1
>>> foo
(3, 5, 2, 4, 78, 2, 1)
>>> foo, bit = foo[:-1], foo[-1]
>>> bit
1
>>> foo
(3, 5, 2, 4, 78, 2)
Or, to work with each value of a tuple starting at the back...
foo = 3,5,2,4,78,2,1
for f in reversed(foo):
print(f) # 1; 2; 78; ...
Or, with the count...
foo = 3,5,2,4,78,2,1
for f, i in enumerate(reversed(foo)):
print(i, f) # 0 1; 1 2; 2 78; ...
Or, to coerce into a list..
bar = [*foo]
#or
bar = list(foo)
ok I figured out a crude way of doing it.
I store the "n" value in the for loop when condition is satisfied in a list (lets call it delList) then do the following:
for ii in sorted(delList, reverse=True):
tupleX.pop(ii)
Any other suggestions are welcome too.
Maybe you want dictionaries?
d = dict( (i,value) for i,value in enumerate(tple))
while d:
bla bla bla
del b[x]
There is a simple but practical solution.
As DSM said, tuples are immutable, but we know Lists are mutable.
So if you change a tuple to a list, it will be mutable. Then you can delete the items by the condition, then after changing the type to a tuple again. That’s it.
Please look at the codes below:
tuplex = list(tuplex)
for x in tuplex:
if (condition):
tuplex.pop(tuplex.index(x))
tuplex = tuple(tuplex)
print(tuplex)
For example, the following procedure will delete all even numbers from a given tuple.
tuplex = (1, 2, 3, 4, 5, 6, 7, 8, 9)
tuplex = list(tuplex)
for x in tuplex:
if (x % 2 == 0):
tuplex.pop(tuplex.index(x))
tuplex = tuple(tuplex)
print(tuplex)
if you test the type of the last tuplex, you will find it is a tuple.
Finally, if you want to define an index counter as you did (i.e., n), you should initialize it before the loop, not in the loop.
A shorter way perhaps:
tup = (0, 1, 2, 3)
new_tup = (*tup[:-2], tup[-1])
print(new_tup) # (0, 1, 3)
The best solution is the tuple applied to a list comprehension, but to extract one
item this could work:
def pop_tuple(tuple, n):
return tuple[:n]+tuple[n+1:], tuple[n]
say you have a dict with tuples as keys, e.g: labels = {(1,2,0): 'label_1'} you can modify the elements of the tuple keys as follows:
formatted_labels = {(elem[0],elem[1]):labels[elem] for elem in labels}
Here, we ignore the last elements.
One solution is to convert to set and bring back to tuple
tupleX = (
"ZAR",
"PAL",
"SEV",
"ALC",
"LPA",
"TFN",)
remove = (
"LPA",
"TFN",)
tuple(set(tupleX) - set(remove))
('ZAR', 'PAL', 'ALC', 'SEV')

Slicing behavior of python range()[:]

I came across an interesting bit of code in a QC review and was surprised by its behavior. I am curious if it is documented anywhere.
for i in range(0, my_array.max(), 3)[:]:
# other code here
I was curious about the need for the [:] after range, so I tested it:
>>> range(0, 10, 3)
range(0, 10, 3)
>>> range(0, 10, 3)[:]
range(0, 12, 3)
The actual sequence defined by these ranges is identical, but I do not see this slicing behavior documented anywhere in the Python range documentation, so I was curious what is actually going on here.
For a moment let's pretend that range still returned a list. Slicing the range object returns a range object which would act as if you were slicing the underlying list. Instead of doing this with a list though, the range object is able to take care of it in constant time using arithmetic.
>>> range(0, 90, 2)[10:23]
range(20, 46, 2)
>>> list(range(0, 90, 2)[10:23])
[20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44]
When you do something like:
range(0, 10, 3)[:]
Python slices it with arithmetic.
My assumption is that when determining the final element it rounds up. It tries to compute the zeroth element in the range to start with. This will be start + step * 0 = 0.
Then Python tries to get the ending element. There are (10 - 0) // 3 + 1 = 4 elements in the range, so the ending element is start + step * n_elements = 0 + 3 * 4 = 12.
I think a few things are mixed here.
range produces slicing behavior, because slicing with non-default indexes makes sense:
>>> list(range(10, 20)[3:7])
[13, 14, 15, 16]
There is an idiom of copying a list (which is mutable) by producing a slice with all default indexes: some_list[:] is equivalent to something like [x for x in some_list].
There is the strange code that does [:] for the range object (or the actual list, if it's Python 2) which makes no sense. The generated range object / list is not referenced anywhere else anyway.
Python documentation lists slicing among "Common Sequence Operations" in a chapter named "Sequence Types — list, tuple, range" (emph. mine). So it's documented, but few people ever read it.

pop/remove items out of a python tuple

I am not sure if I can make myself clear but will try.
I have a tuple in python which I go through as follows (see code below). While going through it, I maintain a counter (let's call it 'n') and 'pop' items that meet a certain condition.
Now of course once I pop the first item, the numbering all goes wrong, how can I do what I want to do more elegantly while removing only certain entries of a tuple on the fly?
for x in tupleX:
n=0
if (condition):
tupleX.pop(n)
n=n+1
As DSM mentions, tuple's are immutable, but even for lists, a more elegant solution is to use filter:
tupleX = filter(str.isdigit, tupleX)
or, if condition is not a function, use a comprehension:
tupleX = [x for x in tupleX if x > 5]
if you really need tupleX to be a tuple, use a generator expression and pass that to tuple:
tupleX = tuple(x for x in tupleX if condition)
Yes we can do it.
First convert the tuple into an list, then delete the element in the list after that again convert back into tuple.
Demo:
my_tuple = (10, 20, 30, 40, 50)
# converting the tuple to the list
my_list = list(my_tuple)
print my_list # output: [10, 20, 30, 40, 50]
# Here i wanna delete second element "20"
my_list.pop(1) # output: [10, 30, 40, 50]
# As you aware that pop(1) indicates second position
# Here i wanna remove the element "50"
my_list.remove(50) # output: [10, 30, 40]
# again converting the my_list back to my_tuple
my_tuple = tuple(my_list)
print my_tuple # output: (10, 30, 40)
Thanks
In Python 3 this is no longer an issue, and you really don't want to use list comprehension, coercion, filters, functions or lambdas for something like this.
Just use
popped = unpopped[:-1]
Remember that it's an immutable, so you will have to reassign the value if you want it to change
my_tuple = my_tuple[:-1]
Example
>>> foo= 3,5,2,4,78,2,1
>>> foo
(3, 5, 2, 4, 78, 2, 1)
foo[:-1]
(3, 5, 2, 4, 78, 2)
If you want to have the popped value,,
>>> foo= 3,5,2,4,78,2,1
>>> foo
(3, 5, 2, 4, 78, 2, 1)
>>> foo, bit = foo[:-1], foo[-1]
>>> bit
1
>>> foo
(3, 5, 2, 4, 78, 2)
Or, to work with each value of a tuple starting at the back...
foo = 3,5,2,4,78,2,1
for f in reversed(foo):
print(f) # 1; 2; 78; ...
Or, with the count...
foo = 3,5,2,4,78,2,1
for f, i in enumerate(reversed(foo)):
print(i, f) # 0 1; 1 2; 2 78; ...
Or, to coerce into a list..
bar = [*foo]
#or
bar = list(foo)
ok I figured out a crude way of doing it.
I store the "n" value in the for loop when condition is satisfied in a list (lets call it delList) then do the following:
for ii in sorted(delList, reverse=True):
tupleX.pop(ii)
Any other suggestions are welcome too.
Maybe you want dictionaries?
d = dict( (i,value) for i,value in enumerate(tple))
while d:
bla bla bla
del b[x]
There is a simple but practical solution.
As DSM said, tuples are immutable, but we know Lists are mutable.
So if you change a tuple to a list, it will be mutable. Then you can delete the items by the condition, then after changing the type to a tuple again. That’s it.
Please look at the codes below:
tuplex = list(tuplex)
for x in tuplex:
if (condition):
tuplex.pop(tuplex.index(x))
tuplex = tuple(tuplex)
print(tuplex)
For example, the following procedure will delete all even numbers from a given tuple.
tuplex = (1, 2, 3, 4, 5, 6, 7, 8, 9)
tuplex = list(tuplex)
for x in tuplex:
if (x % 2 == 0):
tuplex.pop(tuplex.index(x))
tuplex = tuple(tuplex)
print(tuplex)
if you test the type of the last tuplex, you will find it is a tuple.
Finally, if you want to define an index counter as you did (i.e., n), you should initialize it before the loop, not in the loop.
A shorter way perhaps:
tup = (0, 1, 2, 3)
new_tup = (*tup[:-2], tup[-1])
print(new_tup) # (0, 1, 3)
The best solution is the tuple applied to a list comprehension, but to extract one
item this could work:
def pop_tuple(tuple, n):
return tuple[:n]+tuple[n+1:], tuple[n]
say you have a dict with tuples as keys, e.g: labels = {(1,2,0): 'label_1'} you can modify the elements of the tuple keys as follows:
formatted_labels = {(elem[0],elem[1]):labels[elem] for elem in labels}
Here, we ignore the last elements.
One solution is to convert to set and bring back to tuple
tupleX = (
"ZAR",
"PAL",
"SEV",
"ALC",
"LPA",
"TFN",)
remove = (
"LPA",
"TFN",)
tuple(set(tupleX) - set(remove))
('ZAR', 'PAL', 'ALC', 'SEV')

Categories