Multiplying a tuple by a scalar
Question:
I have the following code:
print(img.size)
print(10 * img.size)
This will print:
(70, 70)
(70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70)
I’d like it to print:
(700, 700)
Is there any way to do this without having to write:
print(10 * img.size[0], 10 * img.size[1])
PS: img.size
is a PIL image. I don’t know if that matters anything in this case.
Answers:
Might be a nicer way, but this should work
tuple([10*x for x in img.size])
You can try something like this:
print [10 * s for s in img.size]
It will give you a new list with all the elements you have in the tuple multiplied by 10
The pythonic way would be using a list comprehension:
y = tuple([z * 10 for z in img.size])
Another way could be:
y = tuple(map((10).__mul__, img.size))
img.size = tuple(i * 10 for i in img.size)
There is probably a simpler way than this, but
print map(lambda x: 10*x, img.size)
Will do nearly what you want, although it prints as a list rather than a tuple. Wrap the map
call inside tuple(map...)
if you want it to print as a tuple (parentheses rather than square brackets).
If you have this problem more often and with larger tuples or lists then you might want to use the numpy library, which allows you to do all kinds of mathematical operations on arrays. However, in this simple situation this would be complete overkill.
adding nothing but variety [edit: and inefficiency, and error]..
img_size = (70, 70)
tuple(map(__import__('operator').mul, img_size, len(img_size)*(10,)))
[edit: fixed wrong return type, munged operator use, left the inefficient multiplier generation!]
Solution:
import numpy as np
set1=(70, 70)
tuple(2*np.array(set1))
Explanation: arrays
make direct scalar multiplication possible. Hence the tuple
called set1
here is converted to an array
. I assume you wish to keep using the tuple
, hence we convert the array
back to a tuple
.
This solution is to avoid the explicit and verbose for
loop. I do not know whether it is faster or whether the exact same thing happens in both cases.
In line with the previous answers but using numpy:
import numpy as np
result = tuple(10*np.array(img.size))
You are trying to apply the function on Tuple as a whole.
You need to apply it on individual elements and return a new tuple.
newTuple = tuple([10*x for x in oldTuple])
Remember you cannot change a Tuple.
Simplish thing if you’re writing a bunch of code, but don’t want a more complicated vector library…
class V(tuple):
'''A simple vector supporting scalar multiply and vector add'''
def __new__ (cls, *args):
return super(V, cls).__new__(cls, args)
def __mul__(self,s):
return V( *( c*s for c in self) )
def __add__(self,s):
return V( *( c[0]+c[1] for c in zip(self,s)) )
def __repr__(self):
return "V" + super(V, self).__repr__()
# As long as the "vector" is on the left it just works
xaxis = V(1.0, 0.0)
yaxis = V(0.0, 1.0)
print xaxis + yaxis # => V(1.0, 1.0)
print xaxis*3 + yaxis*5 # => V(3.0, 5.0)
print 3*xaxis # Broke, => (1.0, 0.0, 1.0, 0.0, 1.0, 0.0)
The “V” instances otherwise behave just like tuples. This requires that the “V” instances are all created with the same number of elements. You could add, for example, to __new__
if len(args)!=2: raise TypeError('Must be 2 elements')
to enforce that all the instances are 2d vectors….
Just to overview
import timeit
# tuple element wise operations multiplication
# native
map_lambda = """
a = tuple(range(10000))
b = tuple(map(lambda x: x * 2, a))
"""
# native
tuple_comprehension = """
a = tuple(range(10000))
b = tuple(x * 2 for x in a)
"""
# numpy
using_numpy = """
import numpy as np
a = tuple(range(10000))
b = tuple((np.array(a) * 2).tolist())
"""
print('map_lambda =', timeit.timeit(map_lambda, number=1000))
print('tuple_comprehension =', timeit.timeit(tuple_comprehension, number=1000))
print('using_numpy =', timeit.timeit(using_numpy, number=1000))
Timings on my machine
map_lambda = 1.541315148000649
tuple_comprehension = 1.0838452139996662
using_numpy = 1.2488984129995515
I have the following code:
print(img.size)
print(10 * img.size)
This will print:
(70, 70)
(70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70)
I’d like it to print:
(700, 700)
Is there any way to do this without having to write:
print(10 * img.size[0], 10 * img.size[1])
PS: img.size
is a PIL image. I don’t know if that matters anything in this case.
Might be a nicer way, but this should work
tuple([10*x for x in img.size])
You can try something like this:
print [10 * s for s in img.size]
It will give you a new list with all the elements you have in the tuple multiplied by 10
The pythonic way would be using a list comprehension:
y = tuple([z * 10 for z in img.size])
Another way could be:
y = tuple(map((10).__mul__, img.size))
img.size = tuple(i * 10 for i in img.size)
There is probably a simpler way than this, but
print map(lambda x: 10*x, img.size)
Will do nearly what you want, although it prints as a list rather than a tuple. Wrap the map
call inside tuple(map...)
if you want it to print as a tuple (parentheses rather than square brackets).
If you have this problem more often and with larger tuples or lists then you might want to use the numpy library, which allows you to do all kinds of mathematical operations on arrays. However, in this simple situation this would be complete overkill.
adding nothing but variety [edit: and inefficiency, and error]..
img_size = (70, 70)
tuple(map(__import__('operator').mul, img_size, len(img_size)*(10,)))
[edit: fixed wrong return type, munged operator use, left the inefficient multiplier generation!]
Solution:
import numpy as np
set1=(70, 70)
tuple(2*np.array(set1))
Explanation: arrays
make direct scalar multiplication possible. Hence the tuple
called set1
here is converted to an array
. I assume you wish to keep using the tuple
, hence we convert the array
back to a tuple
.
This solution is to avoid the explicit and verbose for
loop. I do not know whether it is faster or whether the exact same thing happens in both cases.
In line with the previous answers but using numpy:
import numpy as np
result = tuple(10*np.array(img.size))
You are trying to apply the function on Tuple as a whole.
You need to apply it on individual elements and return a new tuple.
newTuple = tuple([10*x for x in oldTuple])
Remember you cannot change a Tuple.
Simplish thing if you’re writing a bunch of code, but don’t want a more complicated vector library…
class V(tuple):
'''A simple vector supporting scalar multiply and vector add'''
def __new__ (cls, *args):
return super(V, cls).__new__(cls, args)
def __mul__(self,s):
return V( *( c*s for c in self) )
def __add__(self,s):
return V( *( c[0]+c[1] for c in zip(self,s)) )
def __repr__(self):
return "V" + super(V, self).__repr__()
# As long as the "vector" is on the left it just works
xaxis = V(1.0, 0.0)
yaxis = V(0.0, 1.0)
print xaxis + yaxis # => V(1.0, 1.0)
print xaxis*3 + yaxis*5 # => V(3.0, 5.0)
print 3*xaxis # Broke, => (1.0, 0.0, 1.0, 0.0, 1.0, 0.0)
The “V” instances otherwise behave just like tuples. This requires that the “V” instances are all created with the same number of elements. You could add, for example, to __new__
if len(args)!=2: raise TypeError('Must be 2 elements')
to enforce that all the instances are 2d vectors….
Just to overview
import timeit
# tuple element wise operations multiplication
# native
map_lambda = """
a = tuple(range(10000))
b = tuple(map(lambda x: x * 2, a))
"""
# native
tuple_comprehension = """
a = tuple(range(10000))
b = tuple(x * 2 for x in a)
"""
# numpy
using_numpy = """
import numpy as np
a = tuple(range(10000))
b = tuple((np.array(a) * 2).tolist())
"""
print('map_lambda =', timeit.timeit(map_lambda, number=1000))
print('tuple_comprehension =', timeit.timeit(tuple_comprehension, number=1000))
print('using_numpy =', timeit.timeit(using_numpy, number=1000))
Timings on my machine
map_lambda = 1.541315148000649
tuple_comprehension = 1.0838452139996662
using_numpy = 1.2488984129995515