简体   繁体   中英

How to join list of integers into one integer python

Given a list of hex integers, I want to end up with one hex integer where the integers are treated as most-significant first and least-significant last.

For example, given... [0x1A, 0xF3, 0x74, 0xA3]

...I want to end up with 0x1AF374A3

In another programming language that I'm familiar with this is a fairly simple operation called "join", but apparently "join" means something else in Python.

I know I can iterate through the list multiplying each subsequent element by 2^something and adding them. I also know I can convert the elements to strings, concatenate them and then convert back to integer. But both those approaches seem clunky. Seems like there should be a simpler / more elegant way. Is there?

Thanks in advance for any help!

I suggest you to switch the values to bytes type in order to concatenate them, them switch back to int type, as follows:

myList = [0x1A, 0xF3, 0x74, 0xA3]
# Conversion to 'bytes'
a = bytes()
for b in myList:
    a += b.to_bytes(1,'big')
# Conversion back to 'int'
a = int.from_bytes(a, 'big')
print(hex(a))  # 0x1af374a3

And you can replace the classic for loop with a generator comprehension passed as parameter to join() method, in order to concatenate the bytes items. It is still readable and a bit shorter, as follows:

myList = [0x1A, 0xF3, 0x74, 0xA3]
a = b''.join(b.to_bytes(1,'big') for b in myList) # Conversion to 'bytes'
a = int.from_bytes(a, 'big')                      # Conversion back to 'int'
print(hex(a))  # 0x1af374a3

Note that if an integer in the input list exceeds 255, then you logically get the error OverflowError: int too big to convert due to b.to_bytes(1,'big') . Of course it can be improved by managing the exception if this case can happen.

I finally may also suggest you the solution using the multiplication by powers of 256, just to show you that it can be achieved in only one-line:

myList = [0x1A, 0xF3, 0x74, 0xA3]
a = sum(nb*(256**i) for i,nb in enumerate(reversed(myList)))
print(hex(a))  # 0x1af374a3
l = [0x1A, 0xF3, 0x74, 0xA3]

merged = ''.join([str(hex(el))[2:] for el in l])

If you need the hex you can get it as:

hex(int(merged, 16)) --> 0x1af374a3

There is nothing extremely inefficient nor ugly in the following code, although it may seem so at a first glance. If you need even more speed you will have to use bitwise operators to jam all ints together.

l = [0x1A, 0xF3, 0x74, 0xA3]
i = int("".join(hex(x)[2:] for x in l), 16)
# And to get the hex representation as requested:
print(hex(i).upper())

There is another way to exploit poor strings in this by using the string formatting like this:

i = int(len(l)*"%x" % tuple(l), 16)
print(hex(i))
from functools import reduce
reduce(lambda x, y: x<<8 | y, [0x1A, 0xF3, 0x74, 0xA3])
# 452162723
'0x{:X}'.format(452162723)
# '0x1AF374A3'

The reverse:

>>> [0x1AF374A3 >> i & 0xff for i in reversed(range(0, 32, 8))]
[26, 243, 116, 163]
>>> [hex(0x1AF374A3 >> i & 0xff) for i in reversed(range(0, 32, 8))]
['0x1a', '0xf3', '0x74', '0xa3']
mylist =[0x1A, 0xF3, 0x74, 0xA3]

most_significant = str(hex(max(mylist)))
print(most_significant + ''.join([str(el).replace('0x', '') for el in mylist if el != max(mylist)]))

0xf326116163

You can convert each to decimal then back to hex but remove the 0x, the join them together and then add 0x at the beginning. format() is good at doing such conversions.

mylist = [0x1A, 0xF3, 0x74, 0xA3]
result = '0x' + ''.join([format(int(n), 'x')for n in [format(i , 'd') for i in mylist]])

Output:

'0x1af374a3'

I think there is a clean and "pythonic" way to solve this, using the Python bytearray type:

foolist = [0x1A, 0xF3, 0x74, 0xA3]
# convert to bytearray and then to a single integer in one line:
x = int.from_bytes(bytearray(foolist), "big")
print(hex(x))
# '0x1af374a3'

In case the most significant byte in the list is at the end of the list, use the parameter "little" instead of "big" in the int.from_bytes function.

In case your list contains an integer bigger than 255, ValueError exception will be raised:

>>> foolist1 = [0xFF, 255]                                                                                 

>>> bytearray(foolist1)                                                                                    
bytearray(b'\xff\xff')


>>> foolist2 = [0xFF, 256]                                                                                 

>>> bytearray(foolist2)                                                                                    
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: byte must be in range(0, 256)

byte must be in range(0, 256)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM