Replace elements in array with class instances

后端 未结 2 1599
盖世英雄少女心
盖世英雄少女心 2021-01-22 20:53

This is similar to this so please read it first to understand what I am trying to do.

Now, I want to make the replacement when I have class instances.Something like:

相关标签:
2条回答
  • 2021-01-22 21:55

    Make the replacement block like this. Also note this assumes your arr will be strictly in multiples of 5 and there will be as many blocks like b1,b2 etc as there are blocks in arr as given in the example.

    for i,b_arr in enumerate(d):
        temp_arr = []
        for j in range(5):
            if j<len(b_arr)
                temp_arr.append(B(arr[i,j],b_arr[j].b))
            else:
                temp_arr.append(B(arr[i,j],b_arr[-1].b))
         d[i] = np.array(temp_arr) ## not sure if this step is right, not too familiar with numpy.
    
    0 讨论(0)
  • 2021-01-22 21:58

    So I add

    print(d.shape)
    print(d)
    

    and get

    2249:~/mypy$ python3 stack42283851.py 
    (2, 1, 4)
    [[[<__main__.B object at 0xb71d760c> <__main__.B object at 0xb71d7aac>
       <__main__.B object at 0xb71d7acc> <__main__.B object at 0xb71e5cec>]]
    
     [[<__main__.B object at 0xb391718c> <__main__.B object at 0xb39171ac>
       <__main__.B object at 0xb39171cc> <__main__.B object at 0xb39171ec>]]]
    

    adding a __repr__ to B I get

    1231:~/mypy$ python3 stack42283851.py 
    (2, 1, 4)
    [[[B(100, a) B(11, b) B(300, c) B(33, d)]]
    
     [[B(45, a) B(65, b) B(77, c) B(88, d)]]]
    

    Adding

    import itertools
    for a,b in itertools.zip_longest(arr[0,:],b1):
         print(a,b)
    

    produces

    1 B(100, a)
    2 B(11, b)
    3 B(300, c)
    4 B(33, d)
    5 None
    

    Changing that to:

    newlist = []
    for a,b in itertools.zip_longest(arr[0,:],b1):
        if b is not None:
            new_b = B(a, b.b)
            last_b = b
        else:
            new_b = B(a, last_b.b)
        newlist.append(new_b)
    print(np.array(newlist))
    

    produces

    [B(1, a) B(2, b) B(3, c) B(4, d) B(5, d)]
    

    Assign that to b1, and repeat for a[1,:] and b2.

    To be a little cleaner I could write that new_b code as a function, and rewrite the loop as a list comprehension.

    Yes, I could modify b in place, e.g.

    b.a = a
    

    but since I need to create a new B object to replace the None, why bother. I can't add the new B object to the original b1 array. So it is simpler to create a new array via a list.


    I can do an in-place change of d and b1 with:

    def replace(a,b):
        b.a = a
    f = np.frompyfunc(replace, 2, 1)
    f(arr[:,None,:4], d)      # produces array of None; ignore
    print(d)
    print(b1)
    
    [[[B(1, a) B(2, b) B(3, c) B(4, d)]]  # chgd d
    
    [[B(6, a) B(7, b) B(8, c) B(9, d)]]]
    [B(1, a) B(2, b) B(3, c) B(4, d)]    # chgd b1
    

    I'm just using frompyfunc as a lazy mans way of broadcasting arr against d and iterating over all elements. Note that I have to change arr to match d shape. Also this does not add any new B(). Obviously you can't do that in-place.


    My B is

    class B():
        def __init__(self, a,b):
            self.a = a
            self.b = b
        def __repr__(self):
            return 'B(%s, %s)'%(self.a, self.b)
    

    Playing with frompyfunc some more:

    getB_b = np.frompyfunc(lambda x: x.b, 1,1)   # fetch b attributes
    print(getB_b(d))
    #[[['a' 'b' 'c' 'd']]
    #
    # [['a' 'b' 'c' 'd']]]
    
    mkB = np.frompyfunc(B, 2,1)   # build array of B() with broadcasting
    print(mkB(arr, ['a','b','c','d','e']))
    # [[B(1, a) B(2, b) B(3, c) B(4, d) B(5, e)]
    #  [B(6, a) B(7, b) B(8, c) B(9, d) B(10, e)]]
    
    print(mkB(arr[:,:4], getB_b(d[:,0,:])))
    # [[B(1, a) B(2, b) B(3, c) B(4, d)]
    #  [B(6, a) B(7, b) B(8, c) B(9, d)]]
    

    edit for comments

    arr1 = np.array([ [1,2],[6,7] ])
    newlist = []
    for a,b in itertools.zip_longest(arr1[0,:],b1):
        if b is not None:
            new_b = B(a, b.b)
            last_b = b
        else:
            new_b = B(a, last_b.b)
        newlist.append(new_b)
    print(np.array(newlist))
    

    produces

    [B(1, a) B(2, b) B(None, c) B(None, d)]
    

    When arr is shorter, a will be None (instead of b); so we need to test for that

    def foo(arr,bn):
        newlist = []
        for a,b in itertools.zip_longest(arr,bn):
            print(a,b)
            if a is None:
                pass
            else:
                if b is not None:
                    new_b = B(a, b.b)
                    last_b = b
                else:
                    new_b = B(a, last_b.b)
                newlist.append(new_b)
        return newlist
    print(np.array(foo(arr1[0,:],b1)))  # arr1 shorter
    print(np.array(foo(arr[0,:], b2)))  # arr longer 
    

    testing:

    1 B(1, a)
    2 B(2, b)
    None B(3, c)
    None B(4, d)
    [B(1, a) B(2, b)]
    
    1 B(6, a)
    2 B(7, b)
    3 B(8, c)
    4 B(9, d)
    5 None
    [B(1, a) B(2, b) B(3, c) B(4, d) B(5, d)]
    

    Nothing special or magical; just a matter making sure I get the if tests and indentation right.

    0 讨论(0)
提交回复
热议问题