2

I have string of bytes that come from embeded system and I use python struct.unpack() to give me tuple of values.

As there are a lot of values I wish to make code more readable. For now I have it done like this:

ArrA = [None] * 3
ArrB = [None] * 2

ArrA[0],ArrA[1],ArrA[2], n, ArrB[0],ArrB[1], crc = (1, 2, 3, 4, 5, 6, 7)
# tuple came from unpack()

Result:

ArrA = [1, 2, 3]
n = 4
ArrB = [5, 6]
crc = 7

Is there some way to shorten arrays? eg ArrA[0],ArrA[1],ArrA[2] to something like ArrA[]*3??

In example arrays are short in real they are pretty long.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
eSlavko
  • 348
  • 3
  • 12

3 Answers3

0

You can get a portion of a tuple or list by using slice syntax:

data = (1, 2, ...)
ArrA = data[:3]

This will give you the first three elements.

Similarly, you can get a slice in the middle:

ArrB = data[5:7]

Note that the indexes define a half open interval, meaning that the last index is not included. You can read more by googling something like "python slice".

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
0

I don't think there's a way to do this with unpacking. If you had only one list, you could use a starred expression*, but not with multiple lists.

Here are some alternatives:

Basic indexing and slicing

t = (1, 2, 3, 4, 5, 6, 7)

ArrA = list(t[:3])
n = t[3]
ArrB = list(t[4:6])
crc = t[6]

One difference is that you won't get an error if t is too long, but you can simply add a check, e.g:

assert len(t) == 7, f"Wrong size: {len(t)}"

Iterator

If you'd rather focus on the number of elements in the lists rather than their positions in t, you can make t into an iterator and consume it a chunk at a time:

it = iter(t)

ArrA = [next(it) for _ in range(3)]
n = next(it)
ArrB = [next(it) for _ in range(2)]
crc = next(it)

This lets you check that t is not too long using this weird syntax:

() = it  # Confirm exhausted

Instead of using list comprehensions, islice is cleaner:

from itertools import islice

ArrA = list(islice(it, 3))
...
ArrB = list(islice(it, 2))
...

Pop from a stack (list)

Python lists are like stacks, with pops happening from the end by default. So we just need to convert t to a list and reverse it to be able to use it similarly to the iterator solution above. It's also possible to pop from the start, but it's less efficient at large scales and I think this is cleaner anyway.

L = list(t)[::-1]

ArrA = [L.pop() for _ in range(3)]
n = L.pop()
ArrB = [L.pop() for _ in range(2)]
crc = L.pop()

() = L  # Confirm exhausted

Footnotes

* For example:

t = (1, 2, 3, 4, 5, 6, 7)

m, *ArrC, crd = t

Result:

m = 1
ArrC = [2, 3, 4, 5, 6]
crd = 7
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • t = (1, 2, 3, 4, 5, 6, 7) m, *ArrC, crd = t, seems perfect but only 1 *param is alowed – eSlavko Jun 24 '23 at 19:10
  • Actually option 1 is good solution. To keep indexes easy I think the best solution is to slice and then del that part. So all indexes are actual length and not position. – eSlavko Jun 24 '23 at 19:14
  • @eSlavko *"seems perfect but only 1 \*param is alowed"* -- That's what I said...? – wjandrea Jun 24 '23 at 23:12
  • @eSlavko I added two more solutions that I would use before `del`. – wjandrea Jun 24 '23 at 23:35
  • @eSlavko Oh, I just got what you're saying. I actually only wrote one option originally. The part at the bottom is just a footnote to demo what *doesn't* work in this case. – wjandrea Jun 24 '23 at 23:38
-2

Based on help I got here this is best solution for me.

t = (1, 2, 3, 4, 5, 6, 7)

ArrA = t[:3]; del t[:3]
n = t[0]; del t[0]
ArrB = t[:3]; del t[:2]
crc = t[0]; del t[0]

All I need to care is length of element, and not indexes. And in the end if t is not empty I have error somewhere.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
eSlavko
  • 348
  • 3
  • 12