How to convert a list of multiple integers into a single integer?

10,056

Solution 1

If you have a list of ints and you want to join them together, you can use map with str to convert them to strings, join them on the empty string and then cast back to ints with int.

In code, this looks like this:

r = int("".join(map(str, x)))

and r now has the wanted value of 135.

This, of course, is a limited approach that comes with some conditions. It requires the list in question to contain nothing else but positive ints (as your sample) or strings representing ints, else the steps of conversion to string might fail or the joining of (negative) numbers will be clunky.

Solution 2

Here is a more mathematical way that does not have to convert back and forth to string. Note that it will only work if 0 <= i <= 9.

>>> x = [1, 3, 5]
>>> sum(d * 10**i for i, d in enumerate(x[::-1]))
135

The idea is to multiply each element in the list by its corresponding power of 10 and then to sum the result.

Solution 3

Using only math (no conversions to or from strings), you can use the reduce function (functools.reduce in Python 3)

b = reduce(lambda total, d: 10*total + d, x, 0)

This makes use of Horner's rule, which factors the polynomial representing the number to reduce the number of multiplications. For example,

1357 = 1*10*10*10 + 3*10*10 + 5*10 + 7     # 6 multiplications
     = ((1*10 + 3)*10 + 5)*10 + 7          # 3 multiplications

As a result, this is faster than computing powers of 10 or creating a string and converting the result to an integer.

>>> timeit.timeit('reduce(lambda t,d: 10*t+d, x, 0)', 'from functools import reduce; x=[1,3,5,7]')
0.7217515400843695
>>> timeit.timeit('int("".join(map(str, [1,3,5,7])))')
1.425914661027491
>>> timeit.timeit('sum(d * 10**i for i, d in enumerate(x[::-1]))', 'x=[1,3,5,7]')
1.897974518011324

In fairness, string conversion is faster once the number of digits gets larger.

>>> import timeit

# 30 digits
>>> setup='from functools import reduce; x=[5, 2, 6, 8, 4, 6, 6, 4, 8, 0, 3, 1, 7, 6, 8, 2, 9, 9, 9, 5, 4, 5, 5, 4, 3, 6, 9, 2, 2, 1]' 
>>> print(timeit.timeit('reduce(lambda t,d: 10*t+d, x, 0)', setup))
6.520374411018565
>>> print(timeit.timeit('int("".join(map(str, x)))', setup))
6.797425839002244
>>> print(timeit.timeit('sum(d * 10**i for i, d in enumerate(x[::-1]))', setup))
19.430233853985555

# 60 digits
>>> setup='from functools import reduce; x=2*[5, 2, 6, 8, 4, 6, 6, 4, 8, 0, 3, 1, 7, 6, 8, 2, 9, 9, 9, 5, 4, 5, 5, 4, 3, 6, 9, 2, 2, 1]' 
>>> print(timeit.timeit('reduce(lambda t,d: 10*t+d, x, 0)', setup))
13.648188541992567
>>> print(timeit.timeit('int("".join(map(str, x)))', setup))
12.864593736943789
>>> print(timeit.timeit('sum(d * 10**i for i, d in enumerate(x[::-1]))', setup))
44.141602706047706

# 120 digits!
>>> setup='from functools import reduce; x=4*[5, 2, 6, 8, 4, 6, 6, 4, 8, 0, 3, 1, 7, 6, 8, 2, 9, 9, 9, 5, 4, 5, 5, 4, 3, 6, 9, 2, 2, 1]' 
>>> print(timeit.timeit('reduce(lambda t,d: 10*t+d, x, 0)', setup))
28.364255172084086
>>> print(timeit.timeit('int("".join(map(str, x)))', setup))
25.184791765059344
>>> print(timeit.timeit('sum(d * 10**i for i, d in enumerate(x[::-1]))', setup))
99.88558598596137

Solution 4

If you don't like map you can always use a list comprehension:

s = [str(i) for i in x]
r = int("".join(s))
Share:
10,056
homelessmathaddict
Author by

homelessmathaddict

This user prefers to keep an air of mystery about them.

Updated on June 15, 2022

Comments

  • homelessmathaddict
    homelessmathaddict almost 2 years

    How do I convert a list in Python 3.5 such as:

    x=[1, 3, 5]
    

    to an integer (int) of 135 ?

  • brianpck
    brianpck over 7 years
    @LoïcFaure-Lacroix The OP specifically asks about an array of integers
  • chepner
    chepner over 7 years
    This is slower than computing the value numerically, but has the benefit of working for bases larger than 10.
  • Loïc Faure-Lacroix
    Loïc Faure-Lacroix over 7 years
    @brianpck yes, I know but generic is sometimes better than not. Btw, the timeit tests are a good way to test things. What the answer doesn't say that the reduce method will get worse with big numbers. It's good with smaller numbers but as soon as it will get numbers with a length of around 30 numbers, the str version will be the fastest solution.
  • Loïc Faure-Lacroix
    Loïc Faure-Lacroix over 7 years
    @chepner it will be faster with large numbers and your version is generally faster with smaller number (30 digit and less on my pc).
  • chepner
    chepner over 7 years
    @LoïcFaure-Lacroix Good point, I tested the two numeric solutions with larger lists, but not the string conversion one. (I was curious about whether the overhead of user-defined functions would lose out, but I guess a linear number of function calls is still better than a quadratic number of multiplications.)
  • Loïc Faure-Lacroix
    Loïc Faure-Lacroix over 7 years
    My guess to explain why the mathematical method will get worse with large numbers is that adding large numbers is harder to do than converting a string to a large number once. The thing is that the string can technically convert the str to a large number directly. Not sure how they are stored in python, but I've seens a couple of BigNumber libararies storing large numbers as strings... But adding large number requires more arithmetic operation as numbers can't be stored completely in memory.
  • chepner
    chepner over 7 years
    The string method still has to do the work in converting a 30-character string to a 30-digit number, but the big difference is that it is done in C, not Python. Large-number libraries tend to work with large bases, for which strings provide a useful storage medium. (cf base-64 encoding)
  • Loïc Faure-Lacroix
    Loïc Faure-Lacroix over 7 years
    Yes, exactly. Your test seems not to be using x thought.
  • chepner
    chepner over 7 years
    Fixed, and added some longer inputs to show str having a slight edge for very large numbers.
  • Loïc Faure-Lacroix
    Loïc Faure-Lacroix over 7 years
    Thumbs up! That's a quite complete answer! Your solution is probably the best one with integers and "real" world number unless it's used for cryptography.
  • asmeurer
    asmeurer over 7 years
    Worth noting that this version will fail if the first integer is 0.
  • Dimitris Fasarakis Hilliard
    Dimitris Fasarakis Hilliard over 7 years
    @asmeurer the solution isn't meant to address all possible inputs, just the one OP provided. I'm actually failing to see how a 0 in the beginning would make it fail though (the int call will drop any leading zeros from the string while converting it).
  • Kroltan
    Kroltan over 7 years
    ...and if you like list comprehensions you can always use a generator expression, and avoid one of the loops: int("".join(str(i) for i in x))
  • Justin
    Justin over 7 years
    If you wanted it to be efficient, would've it be better to do reversed(x) rather than x[::-1]? The latter has to create an entirely new list, but the former just a generator.
  • chepner
    chepner over 7 years
    @asmeurer int doesn't try to infer the base from the string literal; it uses base 10 unless otherwise specified by the optional second argument.
  • asmeurer
    asmeurer over 7 years
    Ah, my mistake. I assumed int would parse strings the same as the tokenizer, but apparently leading zeros are allowed.
  • Yann Vernier
    Yann Vernier almost 6 years
    The factor 10 hardcodes that d is expected to be a single digit. Clarification on that point was requested in a question comment.