2013-08-19 8 views
15
>>> x = numpy.array([[1, 2], 
...     [3, 4], 
...     [5, 6]]) 
>>> [1, 7] in x 
True 
>>> [1, 2] in x 
True 
>>> [1, 6] in x 
True 
>>> [2, 6] in x 
True 
>>> [3, 6] in x 
True 
>>> [2, 3] in x 
False 
>>> [2, 1] in x 
False 
>>> [1, 2, 3] in x 
False 
>>> [1, 3, 5] in x 
False 

Nie mam pojęcia, jak działa __contains__ dla ndarrays. Nie mogłem znaleźć odpowiedniej dokumentacji, gdy jej szukałem. Jak to działa? I czy jest to udokumentowane w dowolnym miejscu?Jak działa __contains__ dla ndarrays?

+0

Spójrz na źródło, a następnie. – Marcin

+4

@Marcin: Źródło jest pochowane gdzieś w stercie C, którego nie rozumiem. Duża część jest nawet autogenerowana, a duża część jest powielana w celu obsługi różnych dtypów i innych różnic. Nie będę tego wszystkiego przeklinać, jeśli nie będę musiał. – user2357112

+3

http://www.mail-archive.com/[email protected]/msg31578.html wydaje się mieć odpowiedź. –

Odpowiedz

6

Znalazłem źródło dla ndarray.__contains__, w numpy/core/src/multiarray/sequence.c. W komentarzu w krajach źródłowych,

thing in x 

jest równoważna

(x == thing).any() 

dla ndarray x, niezależnie od wymiarów x i thing. Ma to sens tylko wtedy, gdy thing jest skalarem; wyniki transmisji, gdy thing nie jest skalarem, powodują dziwne wyniki, które zaobserwowałem, a także dziwności, takie jak array([1, 2, 3]) in array(1), których nie sądziłem, aby spróbować. Dokładne źródło to:

static int 
array_contains(PyArrayObject *self, PyObject *el) 
{ 
    /* equivalent to (self == el).any() */ 

    PyObject *res; 
    int ret; 

    res = PyArray_EnsureAnyArray(PyObject_RichCompare((PyObject *)self, 
                 el, Py_EQ)); 
    if (res == NULL) { 
     return -1; 
    } 
    ret = array_any_nonzero((PyArrayObject *)res); 
    Py_DECREF(res); 
    return ret; 
} 
5

Wydaje się robi numpy „s __contains__ coś takiego dla przypadku 2-D:

def __contains__(self, item): 
    for row in self: 
     if any(item_value == row_value for item_value, row_value in zip(item, row)): 
      return True 
    return False 

[1,7] prace bo th element pierwszego rzędu 0 odpowiada th element [1,7]0. To samo z [1,2] itp. Z numerem [2,6], 6 pasuje do 6 w ostatnim rzędzie. W przypadku [2,3] żaden z elementów nie pasuje do wiersza o tym samym indeksie. [1, 2, 3] jest trywialne, ponieważ kształty nie pasują.

Więcej informacji pod numerem this, a także this ticket.

+0

Wydaje mi się, że "wszystko" byłoby bardziej praktyczne niż "jakiekolwiek", zastanawiam się, dlaczego "numpy" programiści wybrali tę implementację '__contains__'. – Akavall

+1

@Akavall Wydaje się być kompatybilny z Numeric. W Numeric przyjęto, że wartość logiczna tablicy ma wartość "True", jeśli zawiera co najmniej jeden niezerowy element. Numpy podnosi wyjątki, gdy próbuje się użyć tablicy jako wartości logicznej, mówiąc, że należy użyć 'any()' lub 'all()'. W tym przypadku, '__contains __()' API wymusza na Numpy interpretowanie tablicy w kontekście boolowskim, a do tego zdecydowali się na to, co zrobiła funkcja Numeric. Ale zgadzam się, to naprawdę zagmatwane i nie wiem, czy * ktokolwiek * zależy od tego zachowania '__contains __()'. –

+0

Dobra uwaga dotycząca kompatybilności. Dzięki. – Akavall