89

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.

peterh
  • 11,875
  • 18
  • 85
  • 108
devoured elysium
  • 101,373
  • 131
  • 340
  • 557
  • 3
    What's wrong with `(10 * img.size[0], 10 * img.size[1])`? I don't see why you need to overengineer something as simple as a multiplication of 2 integers. Note that this tuple will always have only two elements! – paprika Nov 23 '09 at 09:26
  • 17
    I'm not overengineering. I am asking if there's a nicer, simpler way. Read my post again. – devoured elysium Nov 23 '09 at 09:30
  • 4
    @paprika: ...because the tuple in question may not have a known length. In this case it does (as it did in the case that led me to this question), but coding for an assumed tuple length, repeating the scalar *n* times, and having to get *n* indexes right is kludgy enough to avoid if straightforwardly possible. – J0e3gan Feb 23 '15 at 02:27

12 Answers12

90

Might be a nicer way, but this should work

tuple([10*x for x in img.size])
Hannes Ovrén
  • 21,229
  • 9
  • 65
  • 75
51
img.size = tuple(i * 10 for i in img.size)
mthurlin
  • 26,247
  • 4
  • 39
  • 46
18

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))
ChristopheD
  • 112,638
  • 29
  • 165
  • 179
  • 4
    That second one is awesome... haha. – Mike Boers Nov 26 '09 at 20:29
  • 4
    Neither example captures the point of the question. Both force the programmer to take a simple idea (scalar times matrix multiplication) and deconstruct it. – Zeke Hansell Dec 08 '14 at 20:32
  • 1
    @ZekeHansell What's wrong with "forcing" the programmer to deconstruct his idea? Deconstructing a problem down in order to encapsulate the solution with code is the essence of programming. All of the above answers solve the issue that the asker was asking, in ways that approach the problem at its core, and solve it in repeatable, re-usable bits of code (all one-liners BTW). The code can be easily expanded to accept any arbitrary constant to perform simple scalar-vector multiplication, and the asker has gained a new approach, as well as a new tool in his/her belt. So where's the issue? – Isaac Sep 09 '21 at 15:52
  • You are correct in your analysis/criticism of my comment. Maybe I have grown wiser in the years since my original comment. I've certainly learned something from you. @Isaac – Zeke Hansell Apr 04 '22 at 20:39
10

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.

Mathews Edwirds
  • 65
  • 1
  • 1
  • 9
Mukul Atri
  • 109
  • 1
  • 3
  • 4
    This doesn't work in Python 2 or 3, as far as I can tell. I assume `array` comes from the `array` module? Python expects a character as the first argument to `array`, thus passing only a tuple in will fail with `TypeError: array() argument 1 or typecode must be char (string or ascii-unicode with length 1), not tuple`. Can you expand on this with a more complete example? – Kumba Aug 14 '17 at 22:58
  • 2
    I assume it is a numpy array? – InstaK0 Jun 01 '20 at 16:08
  • It's a numpy array, which is why its import is the first line. It's expected that any non-standard array manipulations are done with numpy. – jgauthier Jan 27 '23 at 19:18
6

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....

Marvin
  • 2,537
  • 24
  • 35
5

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).

sparklewhiskers
  • 910
  • 8
  • 19
4

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.

nikow
  • 21,190
  • 7
  • 49
  • 70
  • While for the *simple* example would be overkill to use numpy, the point of the question seems to be "Does python offer a way mimic operations can be simply expressed in math?" I mean if you have a matrix A = [ 70 70 ] then 2A = [ 140 140 ]. – Zeke Hansell Dec 08 '14 at 20:28
3

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

Serge
  • 7,706
  • 5
  • 40
  • 46
3

In line with the previous answers but using numpy:

import numpy as np
result = tuple(10*np.array(img.size))
user2750362
  • 382
  • 3
  • 6
2

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.

2

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
guesswho
  • 462
  • 4
  • 12
1

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!]

elbeardmorez
  • 580
  • 1
  • 5
  • 13