86

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.

2
  • It appears that you're assuming base 10. True? Commented Jan 29, 2009 at 1:45
  • int(''.join([str(n) for n in numList])) Commented Aug 23, 2022 at 5:52

19 Answers 19

186
# 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)
Sign up to request clarification or add additional context in comments.

8 Comments

I had thought the map function was deprecated in favor of list comprehensions, but now I can no longer find a note to that effect. thank you, I'll be adding that back into my vocabulary.
I assume there's a bug in your "# How I'd probably write it:" and it should be ''.join(map(str, numList)) ? Also, for your "Cleverly" option, you need to int() the result.
TokenMacGuy: you mean this? - artima.com/weblogs/viewpost.jsp?thread=98196 map, reduce, filter, lambda were all to go in 3k originally
Small improvement to the functional method: reduce(lambda x,y: 10*x+y, numList)
|
59

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

3 Comments

No problem, but remember you should probably use what's most readable unless you find it's a bottleneck. I just like timing things. ;-)
I've measured performance of the above function. The results are slightly different e.g. with_accumulator() is faster for small digit_count. See stackoverflow.com/questions/489999/…
I can confirm that with_accumulator looks better on my machine M1 + python3
11
def magic(number):
    return int(''.join(str(i) for i in number))

1 Comment

Nitpick - you can remove the [ ] and do the str'ing as a generation expression. int(''.join(str(i) for i in number)) - it's.. two bytes quicker!
7

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 

2 Comments

That's a strange way to write it in a Python 2.6/3.0 way.. print(''.join(str(x) for x in [1,2,3,4,5])) will work in Python 2.5, 2.6, 3.x, probably more...
@dbr: the purpose was to use the print function. It is not recommended way, that's why I wrote "for completeness".
6
def magic(numbers):
    return int(''.join([ "%d"%x for x in numbers]))

Comments

4

pseudo-code:

int magic(list nums)
{
  int tot = 0

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

  return tot
}

3 Comments

I think you missed the part where he was looking for a python solution :P
That's okay -- Andrew's solution was actually one of the fastest when converted to Python. +1 from me!
It is the fastest solution (@cdleary's implementation in Python) if the list size is less than 30. stackoverflow.com/questions/489999/…
4

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

Comments

4

if the list contains only integer:

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

1 Comment

It may not be obvious to the casual observer, so a warning: this only works with base 10. This also does not appear to work if the items in the list are greater than 9. For example, [1, 250] should equal 1250, but the answer is 260. This answer works as expected: stackoverflow.com/a/37451273/1030576
3

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

Comments

3

Using a generator expression:

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

Comments

2

This seems pretty clean, to me.

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

3 Comments

reduce(lambda x, y: base*x + y, aList, 0) is even cleaner ;)
@Xion: "cleaner"? Not to some folks. reduce() often creates additional problems when used carelessly. I strongly encourage your to post your own answer, since yours is so different from this one.
This does not appear to work. [1, 249] as a base 16 number should equal 505 (256 + 249), but this expression yields a result of 265.
2

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

Comments

1

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

Comments

1

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

Comments

1

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

2 Comments

Don't the elements have to be of type strings for this to work?
The elements in the list are integers, join() will work only on string elements
0

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.

Comments

0

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

Comments

0

Hope this one-line formula can be useful too:

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

Comments

0

A pair of non-strs based approaches.

Assumed that each term in numList is a natural number smaller than 10.

With reduce:

from functools import reduce

numList = [1, 2, 3, 4]

tot = reduce(lambda i, j: i+j[1]*10**(len(numList)-j[0]-1), enumerate(numList), 0)

Used zip/map to couple coefficients with the powers of the base.

The zip-way:

numList = [1, 2, 3]
tot = sum(coef*10**i for coef, i in zip(numList, range(len(numList)-1, -1, -1)))
print(tot)

The map-way:

numList = [1, 2, 3]

base_pows = map(int(10).__pow__, range(len(numList)-1, -1, -1))
tot = sum(map(int.__mul__, numList, base_pows))
print(tot)

Comments

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.