Skip to content Skip to sidebar Skip to footer

How To Fill The Start And The End Of A Unique Entry With The Same Value In Numpy Array?

i have a 1D numpy array. Lets look at the following example a = [255,1,255,255,1,255,255,255,2,2,255,255,255,2,2,3,255,255,255,3] In the above array the unique entries are conside

Solution 1:

have no idea what being pythonic means here, but just my two cents,

import numpy as np    

a = np.array([255,1,255,255,1,255,255,255,2,2,255,255,255,2,2,3,255,255,255,3])

# find the locations of the unique numbers
b = np.where(a != 255)[0]
# find out what the unique numbers are
u = a[b]

for i,v inzip(b, u):
    try:
        if (v == vlast): # found a sandwichif (i != ilast+1): # make sure it has something in between 
                a[ilast+1: i] = v
        else: # make current unique value as the beginning of next sandwich
            vlast, ilast = v, i
    except NameError:
        # initialize the first match
        vlast, ilast = v, i

print(a)

it gives the right answer:

[255   1   1   1   1 255 255 255   2   2   2   2   2   2   2   3   3   3   3   3]

Solution 2:

I used groupby function from itertools module.

Also I used window function from here.

from __future__ import print_function
from  itertools import tee, izip, groupby

a = [255,1,255,255,1,255,255,255,2,2,255,255,255,2,2,3,255,255,255,3]

defgroupby2(iterable):
    '''Used to convert to the second iterable element of "groupby" result to list'''for i in groupby(iterable):
        yield (i[0],list(i[1]))


defwindow(iterable,n):
    els = tee(iterable,n)
    for i,el inenumerate(els):
        for _ inrange(i):
            next(el, None)
    return izip(*els)

defcompress(iterable):
    it = window(groupby2(iterable),3)
    #Creates the iterator which yield the elements in the following manner: (255, [255]), (1, [1]), (255, [255, 255])for ge in it:
        flag = False#Reset the flagprint('\nWindow: {}'.format(ge))

        for value in ge[0][1]: #Yield all the values of the first element of the windowprint('A: {}'.format(value))
                yield value

        if ge[1][0]==255and ge[0][0]==ge[2][0]: #The central element of the window has to be replaced
            flag = True#Flag for correct last window processing        for _ in ge[1][1]: #Replacing the central element of the windowprint('B: {}'.format(ge[0][0]))
                yield ge[0][0]

            next(it,None) #Skip 1 element of the 'it' (which will be advanced by 1 element by for-loop, giving 2 net advances).   #Processing the last 2 elements of the last window.if flag==False: #The central element of the last window hasn't been processed. Proccessing.for value in ge[1][1]:
            print('C: {}'.format(value))
            yield value
    for value in ge[2][1]: #The last element of the window.print('D: {}'.format(value))
        yield value


print('\nInput: {}'.format(a))
output = list(compress((a)))
print('Proram output: {}'.format(output))
print('Goal output  : {}'.format([255,1,1,1,1,255,255,255,2,2,2,2,2,2,2,3,3,3,3,3]))

The code is with debugging messages. I'll live them here since they make it easier to understand how it works. Just delete them if you don't need them.

The output is:

Input: [255, 1, 255, 255, 1, 255, 255, 255, 2, 2, 255, 255, 255, 2, 2, 3, 255, 255, 255, 3]

Window:((255, [255]),(1, [1]),(255, [255, 255]))A:255Window:((1, [1]),(255, [255, 255]),(1, [1]))A:1B:1B:1Window:((1, [1]),(255, [255, 255, 255]),(2, [2, 2]))A:1Window:((255, [255, 255, 255]),(2, [2, 2]),(255, [255, 255, 255]))A:255A:255A:255Window:((2, [2, 2]),(255, [255, 255, 255]),(2, [2, 2]))A:2A:2B:2B:2B:2Window:((2, [2, 2]),(3, [3]),(255, [255, 255, 255]))A:2A:2Window:((3, [3]),(255, [255, 255, 255]),(3, [3]))A:3B:3B:3B:3D:3Proram output: [255, 1, 1, 1, 1, 255, 255, 255, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]
Goal output  : [255, 1, 1, 1, 1, 255, 255, 255, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]

Update Here is a re-factored version:

from __future__ import print_function
from  itertools import tee, izip, groupby

defgroupby2(iterable):
    for i in groupby(iterable):
        yield (i[0],len(tuple(i[1])))


defwindow(iterable,n):
    els = tee(iterable,n)
    for i,el inenumerate(els):
        for _ inrange(i):
            next(el, None)
    return izip(*els)


defsubs(iterable):
    it = window(groupby2(iterable),3)
    for left, middle, right in it:
        yield [left[0]]*left[1]
        if middle[0]==255and left[0]==right[0]:
            yield [left[0]]*middle[1]
            next(it,None)
    ifnot(middle[0]==255and left[0]==right[0]):
        yield [middle[0]]*middle[1]
    yield [right[0]]*right[1]


defchained(iterable):
    for L in subs(iterable):
        for el in L:
            yield el


a = [255,1,255,255,1,255,255,255,2,2,255,255,255,2,2,3,255,255,255,3]        
print('\nInput: {}'.format(a))
output = list(chained((a)))
print('Proram output: {}'.format(output))
print('Goal output  : {}'.format([255,1,1,1,1,255,255,255,2,2,2,2,2,2,2,3,3,3,3,3]))

Solution 3:

A shorter numpy-based solution:

import numpy
a = numpy.array([255,1,255,255,1,255,255,255,2,2,255,255,255,2,2,3,255,255,255,3])

b = [(i, numpy.argmax(a == i), len(a) - numpy.argmax(a[::-1] == i)) for i in numpy.unique(a[a < 255])]

for i in b:
    a[i[1]:i[2]] = i[0]

where b is a list of tuples consisting of (unique value, start index, end index + 1).

Solution 4:

The other solution is to use a window function with 2 items and ifilterfalse on the list of enumerated values.

from __future__ import print_function
from  itertools import tee, izip, ifilterfalse


defwindow(iterable,n):
    els = tee(iterable,n)
    for i,el inenumerate(els):
        for _ inrange(i):
            next(el, None)
    return izip(*els)


defreplace(iterable,placeholder=255):
    it = enumerate(iterable)

    defsave_last(iterable):
        for i in iterable:
            yield i
        replace.last_index = i[0] #Save the last value
    it = save_last(it)

    it = ifilterfalse(lambda x: x[1]==placeholder, it)
    for i,(left,right) inenumerate(window(it,2)):
        if i==0:
            for j inrange(left[0]):
                yield placeholder
        yield left[1]
        if right[0]>left[0]+1:
            if left[1]==right[1]:
                for _ inrange(right[0]-left[0]-1):
                    yield left[1]
            else:
                for _ inrange(right[0]-left[0]-1):
                    yield placeholder
    yield right[1]
    if right[0]<replace.last_index:
        for i inrange(replace.last_index-right[0]):
            yield placeholder


a = [255,1,255,255,1,255,255,255,2,2,255,255,255,2,2,3,255,255,255,3,255,255]        
print('\nInput: {}'.format(a))
output = list(replace(a))
print('Proram output: {}'.format(output))
print('Goal output  : {}'.format([255,1,1,1,1,255,255,255,2,2,2,2,2,2,2,3,3,3,3,3,255,255]))

Here I explain how it works.

Post a Comment for "How To Fill The Start And The End Of A Unique Entry With The Same Value In Numpy Array?"