How do you 'remove' a numpy array from a list of numpy arrays?

后端 未结 4 1988
北海茫月
北海茫月 2021-01-11 13:43

If I have a list of numpy arrays, then using remove method returns a value error.

For example:

import numpy as np

l = [np.array([1,1,1]),np.array([2         


        
相关标签:
4条回答
  • 2021-01-11 14:02

    Here you go:

    list.pop(1)
    

    Update:

    list.pop(list.index(element))
    

    I don't think you can get around traversing the list to find the position of the element. Don't worry about it. Python will, by default use a good searching algorithm to find it at least cost for you.

    0 讨论(0)
  • 2021-01-11 14:04

    Use Python Basic Functionalities

    The following solution uses the list.index(element) method from the list of arrays.

    Searching for a numpy.ndarray needs to be able to hash numpy.ndarray instances. Therefore, we need to implement a hashing algorithm. This is fairly simple, although the code presented looks a bit long, most of the lines are used for checking for edge cases or the addition of comments.

    You can copy paste the code into a file and run it from the command line or a SDK as PyCharm.

    You need to know about

    • [].index(element)
    • hash (hashing and hash collisions)
    • how to hash a numpy array

    Note:

    • hash collisions can lead to wrong decisions, you need to decide yourself about the probability and impact
    • only the first occurence of the array is removed, should there be several with the same data.

    import numpy as np
    
    
    def remove(array, arrays):
        """
        Remove the `array` from the `list` of `arrays`
        Operates inplace on the `list` of `arrays` given
    
        :param array: `np.ndarray`
        :param arrays: `list:np.ndarray`
        :return: None
        """
    
        assert isinstance(arrays, list), f'Expected a list, got {type(arrays)} instead'
        assert isinstance(array, np.ndarray), f'Expected a numpy.ndarray, got {type(array)} instead'
        for a in arrays:
            assert isinstance(a, np.ndarray), f'Expected a numpy.ndarray instances in arrays, found {type(a)} instead'
    
        # Numpy ndarrays are not hashable by default, so we create
        # our own hashing algorithm. The following will do the job ...
        def _hash(a):
            return hash(a.tobytes())
    
        try:
            # We create a list of hashes and search for the index
            # of the hash of the array we want to remove.
            index = [_hash(a) for a in arrays].index(_hash(array))
        except ValueError as e:
            # It might be, that the array is not in the list at all.
            print(f'Array not in list. Leaving input unchanged.')
        else:
            # Only in the case of no exception we pop the array
            # with the same index/position from the original
            # arrays list
            arrays.pop(index)
    
    
    if __name__ == '__main__':
    
        # Let's start with the following arrays as given in the question
        arrays = [np.array([1, 1, 1]), np.array([2, 2, 2]), np.array([3, 3, 3])]
        print(arrays)
    
        # And remove this array instance from it.
        # Note, this is a new instance, so the object id is
        # different. Structure and values coincide.
        remove(np.array([2, 2, 2]), arrays)
    
        # Let's check the result
        print(arrays)
    
        # Let's check, whether our edge case handling works.
        remove(np.array([1, 2, 3]), arrays)
    
    0 讨论(0)
  • 2021-01-11 14:08

    Use Base Functionalities from Python and Numpy

    You can run the following one-liner to get the result ...

    import numpy as np
    
    # Your inputs ...
    l = [np.array([1, 1, 1]), np.array([2, 2, 2]), np.array([3, 3, 3])]
    array_to_remove = np.array([2, 2, 2])
    
    # My result ...
    result = [a for a, skip in zip(l, [np.allclose(a, array_to_remove) for a in l]) if not skip]
    
    print(result)
    

    ... or copy paste the following in a script and experiment a bit.

    You need

    • numpy.allclose to compare numpy arrays up to floating point representation error
    • zip
    • list comprehension
    • the concept of a mask

    Note, ...

    • this solution returns a list without all occurencies of the array we searched for
    • the returned list has references to the np.ndarray instances also referred from the initial list. There are no copies!

    import numpy as np
    
    
    def remove(array, arrays):
        """
        Remove the `array` from the `list` of `arrays`
        Returns list with remaining arrays by keeping the order.
    
        :param array: `np.ndarray`
        :param arrays: `list:np.ndarray`
        :return: `list:np.ndarray`
        """
    
        assert isinstance(arrays, list), f'Expected a list, got {type(arrays)} instead'
        assert isinstance(array, np.ndarray), f'Expected a numpy.ndarray, got {type(array)} instead'
        for a in arrays:
            assert isinstance(a, np.ndarray), f'Expected a numpy.ndarray instances in arrays, found {type(a)} instead'
    
        # We use np.allclose for comparing arrays, this will work even if there are
        # floating point representation differences.
        # The idea is to create a boolean mask of the same lenght as the input arrays.
        # Then we loop over the arrays-elements and the mask-elements and skip the
        # flagged elements
        mask = [np.allclose(a, array) for a in arrays]
        return [a for a, skip in zip(arrays, mask) if not skip]
    
    
    if __name__ == '__main__':
    
        # Let's start with the following arrays as given in the question
        arrays = [np.array([1, 1, 1]), np.array([2, 2, 2]), np.array([3, 3, 3])]
        print(arrays)
    
        # And remove this array instance from it.
        # Note, this is a new instance, so the object id is
        # different. Structure and values coincide.
        _arrays = remove(np.array([2, 2, 2]), arrays)
    
        # Let's check the result
        print(_arrays)
    
        # Let's check, whether our edge case handling works.
        print(arrays)
        _arrays = remove(np.array([1, 2, 3]), arrays)
        print(_arrays)
    
    0 讨论(0)
  • 2021-01-11 14:20

    The problem here is that when two numpy arrays are compared with ==, as in the remove() and index() methods, a numpy array of boolean values (the element by element comparisons) is returned which is interpretted as being ambiguous. A good way to compare two numpy arrays for equality is to use numpy's array_equal() function.

    Since the remove() method of lists doesn't have a key argument (like sort() does), I think that you need to make your own function to do this. Here's one that I made:

    def removearray(L,arr):
        ind = 0
        size = len(L)
        while ind != size and not np.array_equal(L[ind],arr):
            ind += 1
        if ind != size:
            L.pop(ind)
        else:
            raise ValueError('array not found in list.')
    

    If you need it to be faster then you could Cython-ize it.

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