12

Is there any function that can convert a tuple into an integer?

Example:

input = (1, 3, 7)

output = 137
1
  • 1
    Does your tuple have only one digit integers? Do you plan hanle tuples like x = (1, 9, 10, 150)? If it is, could you specify what output should have? Please provide more information. Commented Apr 8, 2012 at 14:43

8 Answers 8

26
>>> reduce(lambda rst, d: rst * 10 + d, (1, 2, 3))
123
Sign up to request clarification or add additional context in comments.

4 Comments

It's worth noting in Python 3.x, reduce() is functools.reduce().
Also +1. I think this is the most readable, and it's also the fastest (see my answer for the comparison in timing).
Arguably the most readable, certainly the most elegant but only the fastest in smaller cases such as this one. The string method is the fastest for large numbers.
The use of reduce() here is essentially a classical method for polynomial factorization, known as Horner's method.
17
>>> x = (1,3,7)
>>> int(''.join(map(str,x)))
137

4 Comments

This solution is the only one so far that can also handle x = (1, 9, 10, 15). It's not clear if the OP wants to handle them too or not.
@RikPoggi I would argue that's a pretty unlikely use case, and you don't actually know that that is the correct output for the case. The OP never specified if he wanted x = (1, 9, 10, 15) to mean 191015 or 15*1+10*10+9*100+1*1000. Either could be considered valid depending on how you approach the problem. Is he considering the input a set of digits or a set of values split by base?
hmm yes although he did not specify it as digits i think we can safely assume they are. However, I don't see how you could ever interpret (1, 9, 10, 15) as 15*1+10*10+9*100+1*1000.
@Lattyware: It's not clear if that might be a use case. I highly doubt that x = (1, 9, 10, 15) should give 2015 instead of 191015, I'd say that it all depends on how that tuple is generated. Anyway I asked the OP, hoping to get some clearance.
4

While converting it to a string then to an int works, it's a somewhat hackish method. We have all the information we need to make a number, namely:

  • The digits.
  • The position of the digits.

As we have this information, we can calculate the number by calculating the value of each unit at each position, then multiplying it up by the digit at said position. We then add together the results and we have our number. This can be done in one line like so:

test = (1, 2, 3)
sum((10**pos)*val for pos, val in enumerate(reversed(test)))

Let's break this down:

>>> list(enumerate(reversed(test)))
[(0, 3), (1, 2), (2, 1)]

So then, if we multiply it up:

>>> list((10**pos)*val for pos, val in enumerate(reversed(test)))
[3, 20, 100]

So we just sum to get 123.

Edit: A note on speed:

python -m timeit "int(''.join(map(str,(1,2,3))))"
100000 loops, best of 3: 2.7 usec per loop

python -m timeit 'sum((10**pos)*val for pos, val in enumerate(reversed((1,2,3))))'
100000 loops, best of 3: 2.29 usec per loop

python -m timeit -s 'from functools import reduce' 'reduce(lambda rst, d: rst * 10 + d, (1, 2, 3))'
1000000 loops, best of 3: 0.598 usec per loop

So if you are going on speed, Andrey Yazu's answer has it. I'm torn as to what I feel is more readable. I always find lambdas ugly somehow, but in general, I think it's still the more readable method.

Edit 2: With very large tuples:

Length 20:

python -m timeit -s "x=tuple(list(range(1,10))*2)" "int(''.join(map(str, x)))"
100000 loops, best of 3: 5.45 usec per loop

python -m timeit -s "x=tuple(list(range(1,10))*2)" "sum((10**pos)*val for pos, val in enumerate(reversed(x)))" 
100000 loops, best of 3: 11.7 usec per loop

python -m timeit -s "x=tuple(list(range(1,10))*2)" -s 'from functools import reduce' 'reduce(lambda rst, d: rst * 10 + d, x)'
100000 loops, best of 3: 4.18 usec per loop

Length 100:

python -m timeit -s "x=tuple(list(range(1,10))*10)" "int(''.join(map(str, x)))"
100000 loops, best of 3: 18.6 usec per loop

python -m timeit -s "x=tuple(list(range(1,10))*10)" "sum((10**pos)*val for pos, val in enumerate(reversed(x)))"
10000 loops, best of 3: 72.9 usec per loop

python -m timeit -s "x=tuple(list(range(1,10))*10)" -s 'from functools import reduce' 'reduce(lambda rst, d: rst * 10 + d, x)'
10000 loops, best of 3: 25.6 usec per loop

Here we see that the fastest method is actually the string operation - however, the reality is you are unlikely to be using this outside of the range of, say, 10 digit numbers - where the reduce() method still dominates speed-wise. I would also argue that the string method is hackish and less clear to the reader, which would normally be the priority over speed.

13 Comments

I was just about to post sum(10**i*x for i,x in enumerate(x[::-1])) but now I won't haha
Isn't this answer similar to mine?
@Abhijit Funny how these things go. I'm not sure if I posted first here, but my answer has plenty of explanation, and using reversed() is a better option than [::-1] as it can be faster and is nicer to read.
Yeah i know, just wanted a shorter answer though, i guess i'll stick to doing things properly even if it makes longer code, especially since enumerate and reversed have such long names...
@jamylak With Python, a big part of the aim of the language is to be readable and maintainable, so I'd always advise working more for readable than short, but each to their own.
|
1

this does not convert the integers to strings and concats them:

>>> sum([(10 ** i) * input[len(input)-i-1] for i in range(len(input))])
123

this is a for-loop in one line.

Comments

1

@Marcin bytearray solution is indeed the fastest one in Python 2.

Following the same line in Python 3 one could do:

>>> plus = ord("0").__add__
>>> int(bytes(map(plus, x)))

Python 3 handles string and bytes in a different way than Python 2, so in order to understand better the situation I did a little timings. The following are the results I got on my machine.

With Python 2.7 (code):

int(str(bytearray(map(plus, x))))           8.40 usec/pass
int(bytearray(map(plus, x)).decode())       9.85 usec/pass
int(''.join(map(str, x)))                   11.97 usec/pass
reduce(lambda rst, d: rst * 10 + d, x)      22.34 usec/pass

While with Python 3.2 (code):

int(bytes(map(plus, x)))                    7.10 usec/pass
int(bytes(map(plus, x)).decode())           7.80 usec/pass
int(bytearray(map(plus,x)).decode())        7.99 usec/pass
int(''.join(map(str, x)))                   17.46 usec/pass
reduce(lambda rst, d: rst * 10 + d, x)      19.03 usec/pass

Judge by yourselves :)

Comments

1

How about:

In [19]: filter(set('0123456789').__contains__,str((1,2,3)))
Out[19]: '123'

I believe this is the simplest solution.

A very fast solution is:

plus=ord("0").__add__ # separate out for readability; bound functions are partially-applied functions
int(str(bytearray(map(plus,x)))) #str is necessary

How that stacks up against the next-fastest solution:

$ python -m timeit -s 'x=tuple(list(range(1,10))*10)' 'plus=ord("0").__add__;int(str(bytearray(map(plus,x))))'
10000 loops, best of 3: 47.7 usec per loop

$ python -m timeit -s "x=tuple(list(range(1,10))*10)" "int(''.join(map(str, x)))"
10000 loops, best of 3: 59 usec per loop

5 Comments

using __functions__ isn't a good idea, especially when there are other options available, right?
@0xc0de Why not? str is never going to lose the __contains__ method, and this avoids both (python) function-call, and operator-resolution overheads.
Note that in Python 3.x, your first example returns ['1', '2', '3'], not '123', and the requested output either way was an int - not a string.
And with regards to referencing __add__() a better option is to use functools.partial() and operator.add() and do plus = partial(add, ord("0")).
@Lattyware In possible what way is it better to use partial? As to the behaviour of the first example, I imagine you can work out how to change it to an int; and Python 3 simply makes some strange changes to the language.
1

The simplest method to change a tuple into a number is to use string formating.

input = (1, 3, 7)
output = int('{}{}{}'.format(input[0], input[1], input[2]))

# TEST
print(output) # 137
print(type(output)) # <class 'int'>

Comments

0

Just another way to do it

>>> sum(n*10**i for (i,n) in enumerate(input[::-1]))
137

and yet another

>>> int(str(input).translate(None,'(,) '))
137

1 Comment

Maybe better: reverse(input) instead of input[::-1].

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.