Convert list of ints to one number?

I have a list of integers that I would like to convert to one number like:

numList = [1, 2, 3]
num = magic(numList)

print num, type(num)
>>> 123, <type 'int'>

What is the best way to implement the magic function?

EDIT
I did find this, but it seems like there has to be a better way.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

# Over-explaining a bit:
def magic(numList):         # [1,2,3]
    s = map(str, numList)   # ['1','2','3']
    s = ''.join(s)          # '123'
    s = int(s)              # 123
    return s


# How I'd probably write it:
def magic(numList):
    s = ''.join(map(str, numList))
    return int(s)


# As a one-liner  
num = int(''.join(map(str,numList)))


# Functionally:
s = reduce(lambda x,y: x+str(y), numList, '')
num = int(s)


# Using some oft-forgotten built-ins:
s = filter(str.isdigit, repr(numList))
num = int(s)

Method 2

Two solutions:

>>> nums = [1, 2, 3]
>>> magic = lambda nums: int(''.join(str(i) for i in nums)) # Generator exp.
>>> magic(nums)
123
>>> magic = lambda nums: sum(digit * 10 ** (len(nums) - 1 - i) # Summation
...     for i, digit in enumerate(nums))
>>> magic(nums)
123

The map-oriented solution actually comes out ahead on my box — you definitely should not use sum for things that might be large numbers:

Timeit Comparison

import collections
import random
import timeit

import matplotlib.pyplot as pyplot

MICROSECONDS_PER_SECOND = 1E6
FUNS = []
def test_fun(fun):
    FUNS.append(fun)
    return fun

@test_fun
def with_map(nums):
    return int(''.join(map(str, nums)))

@test_fun
def with_interpolation(nums):
    return int(''.join('%d' % num for num in nums))

@test_fun
def with_genexp(nums):
    return int(''.join(str(num) for num in nums))

@test_fun
def with_sum(nums):
    return sum(digit * 10 ** (len(nums) - 1 - i)
        for i, digit in enumerate(nums))

@test_fun
def with_reduce(nums):
    return int(reduce(lambda x, y: x + str(y), nums, ''))

@test_fun
def with_builtins(nums):
    return int(filter(str.isdigit, repr(nums)))

@test_fun
def with_accumulator(nums):
    tot = 0
    for num in nums:
        tot *= 10
        tot += num
    return tot

def time_test(digit_count, test_count=10000):
    """
    :return: Map from func name to (normalized) microseconds per pass.
    """
    print 'Digit count:', digit_count
    nums = [random.randrange(1, 10) for i in xrange(digit_count)]
    stmt = 'to_int(%r)' % nums
    result_by_method = {}
    for fun in FUNS:
        setup = 'from %s import %s as to_int' % (__name__, fun.func_name)
        t = timeit.Timer(stmt, setup)
        per_pass = t.timeit(number=test_count) / test_count
        per_pass *= MICROSECONDS_PER_SECOND
        print '%20s: %.2f usec/pass' % (fun.func_name, per_pass)
        result_by_method[fun.func_name] = per_pass
    return result_by_method

if __name__ == '__main__':
    pass_times_by_method = collections.defaultdict(list)
    assert_results = [fun([1, 2, 3]) for fun in FUNS]
    assert all(result == 123 for result in assert_results)
    digit_counts = range(1, 100, 2)
    for digit_count in digit_counts:
        for method, result in time_test(digit_count).iteritems():
            pass_times_by_method[method].append(result)
    for method, pass_times in pass_times_by_method.iteritems():
        pyplot.plot(digit_counts, pass_times, label=method)
    pyplot.legend(loc='upper left')
    pyplot.xlabel('Number of Digits')
    pyplot.ylabel('Microseconds')
    pyplot.show()

Method 3

def magic(number):
    return int(''.join(str(i) for i in number))

Method 4

def magic(numbers):
    return int(''.join([ "%d"%x for x in numbers]))

Method 5

Just for completeness, here’s a variant that uses print() (works on Python 2.6-3.x):

from __future__ import print_function
try: from cStringIO import StringIO
except ImportError:
     from io import StringIO

def to_int(nums, _s = StringIO()):
    print(*nums, sep='', end='', file=_s)
    s = _s.getvalue()
    _s.truncate(0)
    return int(s)

Time performance of different solutions

I’ve measured performance of @cdleary’s functions. The results are slightly different.

Each function tested with the input list generated by:

def randrange1_10(digit_count): # same as @cdleary
    return [random.randrange(1, 10) for i in xrange(digit_count)]

You may supply your own function via --sequence-creator=yourmodule.yourfunction command-line argument (see below).

The fastest functions for a given number of integers in a list (len(nums) == digit_count) are:

  • len(nums) in 1..30
    def _accumulator(nums):
        tot = 0
        for num in nums:
            tot *= 10
            tot += num
        return tot
  • len(nums) in 30..1000
    def _map(nums):
        return int(''.join(map(str, nums)))
    
    def _imap(nums):
        return int(''.join(imap(str, nums)))

Figure: N = 1000

|------------------------------+-------------------|
| Fitting polynom              | Function          |
|------------------------------+-------------------|
| 1.00  log2(N)   +  1.25e-015 | N                 |
| 2.00  log2(N)   +  5.31e-018 | N*N               |
| 1.19  log2(N)   +      1.116 | N*log2(N)         |
| 1.37  log2(N)   +      2.232 | N*log2(N)*log2(N) |
|------------------------------+-------------------|
| 1.21  log2(N)   +      0.063 | _interpolation    |
| 1.24  log2(N)   -      0.610 | _genexp           |
| 1.25  log2(N)   -      0.968 | _imap             |
| 1.30  log2(N)   -      1.917 | _map              |

Figure: N = 1000_000

To plot the first figure download cdleary.py and make-figures.py and run (numpy and matplotlib must be installed to plot):

$ python cdleary.py

Or

$ python make-figures.py --sort-function=cdleary._map 
> --sort-function=cdleary._imap 
> --sort-function=cdleary._interpolation 
> --sort-function=cdleary._genexp --sort-function=cdleary._sum 
> --sort-function=cdleary._reduce --sort-function=cdleary._builtins 
> --sort-function=cdleary._accumulator 
> --sequence-creator=cdleary.randrange1_10 --maxn=1000

Method 6

pseudo-code:

int magic(list nums)
{
  int tot = 0

  while (!nums.isEmpty())
  {
    int digit = nums.takeFirst()
    tot *= 10
    tot += digit
  }

  return tot
}

Method 7

This method works in 2.x as long as each element in the list is only a single digit. But you shouldn’t actually use this. It’s horrible.

>>> magic = lambda l:int(`l`[1::3])
>>> magic([3,1,3,3,7])
31337

Method 8

Using a generator expression:

def magic(numbers):
    digits = ''.join(str(n) for n in numbers)
    return int(digits)

Method 9

A one-liner without needing to cast to and from str

def magic(num):
    return sum(e * 10**i for i, e in enumerate(num[::-1]))

Method 10

if the list contains only integer:

reduce(lambda x,y: x*10+y, list)

Method 11

This seems pretty clean, to me.

def magic( aList, base=10 ):
    n= 0
    for d in aList:
        n = base*n + d
    return n

Method 12

I found some examples are not compatible with python 3 I test one from @Triptych

s = filter(str.isdigit, repr(numList))
num = int(s)

in python 3 it’s gonna give error

TypeError: int() argument must be a string, a bytes-like object or a number, not 'filter'

i think the more simple and compatible way would be

def magic(num_list):
    return int("".join(map(str, num_list)))

Method 13

This may be helpful

def digits_to_number(digits):
    return reduce(lambda x,y : x+y, map(str,digits))

print digits_to_number([1,2,3,4,5])

Method 14

If you happen to be using numpy (with import numpy as np):

In [24]: x
Out[24]: array([1, 2, 3, 4, 5])

In [25]: np.dot(x, 10**np.arange(len(x)-1, -1, -1))
Out[25]: 12345

Method 15

I found this thread while trying to convert a list to the real value of the underlying int in terms of a C-style pointer, but none of the other answers appear to work for this case. I think the following solution works as intended and could be useful to others even though it doesn’t necessarily answer the original question.

def listToInt(x, reverseBytes=False):
  if reverseBytes:
    x = x[::-1]
  return reduce(lambda x,y: x*256+y, x)

listToInt([1, 249]) == 505

listToInt([249, 1], True) == 505

The primary value of this is to emulate the behavior of casting a byte array to another data type, e.g. uint16, which Python can’t seem to do natively, on either a big or little endian system.

Method 16

Too late for the party here is the approch without converting to string

x=0
k=len(a)-1
for i in a:
    x+=(10**k)*i
    k-=1

Method 17

I think this seems to be the simplest solution with no need for any fcn

res = int(''.join(numList))

NOTE: This implementation is in Python 3

Method 18

Hope this one-line formula can be useful too:

s=sum([numlist[i] * 10**(len(numlist)-i-1) for i in range(len(numlist))])


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x