How to increment values in a list within specific range

Question:

I have a list l =[253, 59, 2, 0, 0, 0, 0, 0] and I want to set a range of (0, 255) for each element in the list. I want to implement it in python. I want to increment the elements one by one such that when it reaches the max range the element should reset to 0 and the next element should increment by 1

The output should look like this after every iteration:

l =[253, 59, 2, 0, 0, 0, 0, 0]
l =[254, 59, 2, 0, 0, 0, 0, 0]
l =[255, 59, 2, 0, 0, 0, 0, 0]
l =[0, 60, 2, 0, 0, 0, 0, 0]
l =[1, 60, 2, 0, 0, 0, 0, 0]
.
.
.
.
l =[255, 60, 2, 0, 0, 0, 0, 0]
l =[0, 61, 2, 0, 0, 0, 0, 0]
Asked By: dvpi

||

Answers:

One option in pure python:

l = [253, 59, 2, 0, 0, 0, 0, 0]

pos = 0
n_iter = 10
step = 0
for step in range(n_iter):
    for pos in range(len(l)):
        if l[pos] < 255:
            l[pos] += 1
            break
        else:
            l[pos] = 0
    print(f'step {step+1}: {l}')

Output:

step 1: [254, 59, 2, 0, 0, 0, 0, 0]
step 2: [255, 59, 2, 0, 0, 0, 0, 0]
step 3: [0, 60, 2, 0, 0, 0, 0, 0]
step 4: [1, 60, 2, 0, 0, 0, 0, 0]
step 5: [2, 60, 2, 0, 0, 0, 0, 0]
step 6: [3, 60, 2, 0, 0, 0, 0, 0]
step 7: [4, 60, 2, 0, 0, 0, 0, 0]
step 8: [5, 60, 2, 0, 0, 0, 0, 0]
step 9: [6, 60, 2, 0, 0, 0, 0, 0]
step 10: [7, 60, 2, 0, 0, 0, 0, 0]
Answered By: mozway

with loop,

array = [253, 59, 2, 0, 0, 0, 0, 0]
index = 0
while index < len(array):
    while array[index]<256:
        array[index] += 1
        print(array)
    array[index] = 0
    index += 1
Answered By: sahasrara62

One way with a loop:

def inc_list(l):
    for i in range(len(l)):
        l[i] += 1
        if l[i] > 255:
            l[i] = 0
        else:
            return

for _ in range(300):
    print(l)
    inc_list(l)

Alternatively, a recursive solution:

def inc_list(l):
    if not l:
        return []
    elif l[0] == 255:
        return [0] + inc_list(l[1:])
    else:
        return [l[0] + 1] + l[1:]

for _ in range(300):
    print(l)
    l = inc_list(l)
Answered By: Stuart

tl;dr: one-liner is

import struct
list(struct.pack('<Q', struct.unpack('<Q', bytes(start))[0]+1))

1- Counting in 64 bits

Just to provide another view, this what you seem to do is counting in a list of 8 bytes representing a 64 bits integer, little-endian… Why don’t you just do that?

def plusOne(l):
   n=0
   b=1
   for dg in l:
       n+=b*dg
       b*=256
   n+=1
   res=[]
   for i in range(len(l)):
       res.append(n%256)
       n//=256
   return res

As is, this answer is not faster than the others. It is even way slower, I surmise (haven’t timeit it. But, well, it is obviously more complex).

But if what you want to have is just a counter, then you could simplify by keeping just an integer as state value, and generate the list

2- Iterator

def listCounter(start, size):
    while True:
        res=[]
        x=start
        for i in range(size):
            res.append(x%256)
            x//=256
        yield res
        start+=1

myiter=listCounter(254, 8)
print(next(myiter))
print(next(myiter))
for _,l in zip(range(20),listCounter(510,8)):
    print(l)

3- Struct (using internal representation)

Since that is how 8 bytes integer are counted on the hardware, you can even rely on the cpu to do that, rather than trying to imitate it in python.

import struct
l=[254, 255, 0, 0, 1, 0, 0, 0]
nextl=list(struct.pack('<Q', struct.unpack('<Q', bytes(l))[0]+1))

Or in the for of an iterator

import struct
def listCounter(start):
    while True:
        yield start
        start=list(struct.pack('<Q', struct.unpack('<Q', bytes(start))[0]+1))

for _,l in zip(range(10), listCounter([254,255,0,0,1,0,0,0])):
   print(l)
[254, 255, 0, 0, 1, 0, 0, 0]
[255, 255, 0, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 1, 0, 0, 0]
[1, 0, 1, 0, 1, 0, 0, 0]
[2, 0, 1, 0, 1, 0, 0, 0]
[3, 0, 1, 0, 1, 0, 0, 0]
[4, 0, 1, 0, 1, 0, 0, 0]
[5, 0, 1, 0, 1, 0, 0, 0]
[6, 0, 1, 0, 1, 0, 0, 0]
[7, 0, 1, 0, 1, 0, 0, 0]

Explanation

bytes(l) is a byte array containing the 8 bytes in l
bytes(l) -> b'xfexffx00x00x01x00x00x00'
Those 8 bytes are the 64 bits representation of a number. Which we can extract by struct.unpack, specifying the format <Q (64 bits integer, little-endian, that is increasing first bytes first)
struct.unpack('<Q', bytes(l)) → (4295032830,)
It is in form of tuple because we could have asked for a succession of different numbers. So
struct.unpack('<Q', bytes(l))[0] → 4295032830
We can increment it
struct.unpack('<Q', bytes(l))[0]+1 → 4295032831
And we can get the 64 bits bytes array representation of this new integer, using pack
struct.pack('<Q',struct.unpack('<Q', bytes(l))[0]+1) → b'xffxffx00x00x01x00x00x00'
This bytes array are just numbers between 0 and 255, we can easily get them converting it to a list
list(struct.pack('<Q',struct.unpack('<Q', bytes(l))[0]+1)) → [255, 255, 0, 0, 1, 0, 0, 0]

Answered By: chrslg

The problem is equivalent to finding representations of consecutive integers in positional numeral system with base 256 (but you could use mixed bases as well).

numpy ravel and unravel

For smaller lists you could find integer that has a form l = [253, 59, 2, 0]

value = np.ravel_multi_index(l, [256] * 4, order='F') #sets value to 146429

And then use np.unravel_index to get back representations of first, say, 5 integers:

np.transpose(np.unravel_index(np.arange(value, value+5), [256]*4, order='F'))
>>> array([[253,  59,   2,   0],
           [254,  59,   2,   0],
           [255,  59,   2,   0],
           [  0,  60,   2,   0],
           [  1,  60,   2,   0]], dtype=int64)

Larger cases

In your case dimension = [256] * 8 is required. This is too large because integers can’t exceed 2**63 in numpy and ValueError would be thrown. In this case you could implement your own way that replaces np.ravel_multi_index and np.unravel_index:

shape = np.cumprod([1, 256, 256, 256, 256, 256, 256, 256], dtype=np.int64)
value = np.dot(l, shape) #same 146429

def unravel(values, shape=[256] * 8):
    steps = len(values)
    result_arr = np.empty(shape=(len(shape), steps), dtype=int)
    for j in range(len(shape)):
        result_arr[j] = values % shape[j]
        values =  values // shape[j]
    return np.transpose(result_arr)

unravel(np.arange(value, value+5))
>>> array([[253,  59,   2,   0,   0,   0,   0,   0],
           [254,  59,   2,   0,   0,   0,   0,   0],
           [255,  59,   2,   0,   0,   0,   0,   0],
           [  0,  60,   2,   0,   0,   0,   0,   0],
           [  1,  60,   2,   0,   0,   0,   0,   0]])

Note that only 8 iterations are required in all cases so it should be faster than Python – only ways.

Answered By: mathfux
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.