There is an array in which each element is a two-byte word. How to swap the first and second bytes of each element?
4 answers
Having an array array in which each element is stored in at least two bytes, to change the order of bytes, it suffices to call the array.byteswap() method :
>>> import array >>> a = array.array('h', [1, 32767]) >>> a.tobytes() b'\x01\x00\xff\x7f' >>> a.byteswap() >>> a.tobytes() b'\x00\x01\x7f\xff' >>> a array('h', [256, -129]) It can be seen that the numbers were stored in an array using native byte order ( sys.byteorder is equal to 'little' on my system — from "low to high"). After calling .byteswap() byte order was changed to "from .byteswap() to low", which changed the stored values (which are always interpreted in sys.byteorder ):
>>> import sys >>> 1 .to_bytes(2, sys.byteorder) b'\x01\x00' # от "младшего к старшему" >>> 1 .to_bytes(2, 'big') b'\x00\x01' # "от старшего к младшему" >>> int.from_bytes(_, 'little') # интепретируя как от "младшего к старшему" 256 The same API works for numpy arrays:
>>> import numpy >>> a = numpy.array([1, 32767], dtype='h') >>> a array([ 1, 32767], dtype=int16) >>> a.tobytes() b'\x01\x00\xff\x7f' >>> a.byteswap(True) # inplace array([ 256, -129], dtype=int16) >>> a.tobytes() b'\x00\x01\x7f\xff' It is seen that identical results are obtained.
If you have a Python list with Python numbers [1, 32767] , then the concept of byte order does not make much sense. As a matter of fact, Python int in memory is represented by implementation and for most applications it does not matter. For example, in CPython, int consists of sys.int_info.bits_per_digit -bit digits, each of which takes sys.int_info.sizeof_digit bytes, where these digits go from the lowest to the highest position and the absolute value of Python int is :
SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i) A bit of magic with numbers. First, we divide the two-byte value into two single-byte ones:
lo = value % 256 hi = value // 256 Now we collect back to two-byte:
value == hi * 256 + lo # всегда должно быть верно rev_value = lo * 256 + hi # то, что хотим по условию, поменяли байты As a result, if you write shorter as a function:
rev_bytes = lambda v: v % 256 * 256 + v // 256 Applying this function to all elements of the list, for example, using map , we get a complete solution.
Remark 1 : To increase performance, this should be written through logical bitwise operations, replacing i // 256 with i >> 8 , i * 256 with i << 8 , and + with | :
rev_bytes = lambda v: ((v % 256) << 8) | (v >> 8) Warning : be careful with the order of the operations, you can get an unexpected result if you put the brackets in the wrong way or not at all.
Note 2 : Another possible optimization here is memorialization. If this function needs to be applied many times, it will be faster to save its results for all two-byte numbers into an array once, and to replace the function call by taking the necessary element from this array.
UPD:
Let MyArray be a list of two-byte numbers stored in an int . Then the new array will be like this:
NewArray = list(map(lambda v: ((v % 256) << 8) | (v >> 8), MyArray)) map apply the function of changing bytes in places to each element of MyArray . list will make a list of it.
- oneIf not difficult, write the full code - Denis Leonov
- 1- What type of
value? Python int is not a "double-byte word". 2- It’s not worth talking without measurements (even C is not clear if there is a difference, not to mention Python) 3- mention explicitly the behavior for negative numbers 4-v % 256asv & 0xFFwrite. - jfs
def reverse(input): L = len(input) if L%2 <> 0: return 'Error' #Ошибка в случае когда L не кратно 2 else: Res = '' L = L//2 for i in range(L): T = input[i*2] + input[i*2+1] Res = T + Res T = '' return(Res); Arr - your array of numbers (array of strings, each line of the form A1F6... , in your case A65D , for example)
Call code:
ArrLength = len(Arr) for i in range(ArrLength): Arr[i] = reverse(Arr[i]) - oneYou need to tweak the code a bit: replace
<>with!=. And it would be good to screw the conversion to hex and back with adding the necessary number of zeros to the beginning of the line. - diversenok - @diversenok then you have to somehow figure out which side to add zeros. Is not it? - Denis Leonov
- oneJust two-byte numbers written as strings are not always 4 characters long. Ok, I'll write myself:
IntToHex = lambda a: '0' * (6 - len(hex(a))) + hex(a)[2:]- diversenok - My - the easiest option) - Denis Leonov
You can try to "serialize" the Python element into a binary binary representation, then swap bytes.
I assume that the elements are stored as numbers.
from struct import pack, unpack def reorder_bytes( value ): return unpack( "H", pack( "H", value )[::-1] )[0] # модуль struct используется для конвертации С структур в python объекты # H --- unsigned int16 # pack с "H" сконвертирует python int в бинарную строку длиной в 2 байта, соответствующую Си представление unsigned int16 # unpack возвращает tuple из распакованных данных, нужный нам результат будет в первом элементе. - This function returns a
tuplewith one element, it would be nice to unpack it. - diversenok - Added unpacking. - Arnial
Endiannessbefore / during conversion? - MaxU