K
Previous observationsThe input data you provide, converted to bits that indicate the NaN positions, produce the binary value:001001000001
but since that is 12 bits and not 16 how do you decide where to split it into two groups and how to fill the resulting in incomplete bytes with zeros?On the other hand I note that the chosen example is a bit unfortunate, because the first byte is "capicúa" (00100100) and it is not clear therefore whether it should be read from right to left or backward. Only after examining your code I realize that it has been built "outside", that is, that the first value of the list (11.325) gives rise to the least significant bit of the result. This is counterintuitive, but I guess that's how you need it.It therefore seems that your algorithm would be to take the bits of 8 in 8 but interpreted "from less to greater" to build the first byte and do the same with the remaining ones, filling with zeros "on the right" (which becomes by the left considering that we process them from less to greater weight). I insist, quite confusing.On the other hand I do not see how the receiver of these bytes can decode them correctly without knowing that the total significant bits is 12. Without that fact, you wouldn't know what the filling bits are.ImplementationHaving said all of the above, another implementation that results exactly what you ask can be achieved by making use of the library bitarray. With this bookstore not only reduces the code (to a couple of lines) and becomes more readable, but it will also be faster because bitarray is implemented internally in C.from bitarray import bitarray
lista = [11.325,99.3696,'NaN','0',0,'NaN',0,0,0,88,0,'NaN']
b = bitarray((x == "NaN" for x in lista), endian="little")
print("Servidor recibirá", b.tobytes())
Attention to the parameter endian="little" that is the one that makes the bits inside the bitarray interpret "from left to right" when it is converted into bytes, as in your implementation.The output is the same as when your code is executed:Servidor recibirá b'$\x08'
Note, however, that is not the result you described in your statement. The first byte is the ascii code of '$', which is 00100100. The second byte is code 0x08, which is 00001000 and no 00000001 as you put in the description. However 0x08 is what also produced your code for this example.Without external librariesSince the OP indicates in a comment that it is working with micropython and prefers not to use external libraries, here I offer another implementation in pure python:lista = [11.325,99.3696,'NaN','0',0,'NaN',0,0,0,88,0,'NaN']
binario = "".join("1" if v == "NaN" else "0" for v in lista)
numeros = [int(binario[i:i+8][::-1],2) for i in range(0, len(binario),8)]
final = [b.to_bytes(1, "little") for b in lista_bytes]
print('Servidor recibirá:',final)
The result is expected: [b'$', b'\x08'].Some tricks used in the code:"1" if v == "NaN" else "0" for v in lista is a generator expression that is generating a series of "1" and "0" from the list. It is passed as parameter to "".join() so that everyone joins in a single chain. In the example that resulting chain would contain "001001000001"int(binario[i:i+8][::-1],2) takes 8 characters from the string binarioincluding between position i e i+8. It turns them around (the [::-1] it's for that) and it goes that chain to int(..., 2) that interprets it in base 2 to produce an integer.The above is used in a list understanding to produce a list of integers from the contained chain binario. In this example the resulting number list is [36, 8]. These are already the (numeric) values of the bytes to send.To convert them into byte type data is used int.to_bytes() which requires two parameters. The first would be the number of bytes to generate (1 in this case) and the second the endianity. Being a single byte, the same gives to put "little" that "big" in this case.Notes that the use of to_bytes() unnecessary use of the module struct.Adapted to micropythonIt seems that micropython does not implement all language, but a subset. In particular it does not support the parameter step in the slices, which prevents using the trick [::-1] to turn the chain around.It can be done using reversed()but it is necessary to convert the result into a chain again with "".join(). The code is far-fetched, but it works (this time I checked with the online interpreter) https://micropython.org/unicorn/ )lista = [11.325,99.3696,'NaN','0',0,'NaN',0,0,0,88,0,'NaN']
binario = "".join("1" if v == "NaN" else "0" for v in lista)
numeros = [int("".join(reversed(binario[i:i+8])),2) for i in range(0, len(binario),8)]
final = [b.to_bytes(1, "little") for b in numeros]
print('Servidor recibirá:',final)
It is not the same "turning each byte" as I have done in the previous code than "turning the list" before processing it, as in this last case we would not only change the bits weight, but also order the bytes.