\chapter{Object Array}
\label{cha:object-array}
\declaremodule{extension}{numarray.objects}
\index{object array}

\section{Introduction}
\label{sec:objectarray-intro}

\code{numarray}, like \code{Numeric}, has support for arrays of objects in
addition to arrays of numbers.  Arrays of objects are supported by the
\code{numarray.objects} module.  The \index{ObjectArray} \code{ObjectArray}
class is used to represent object arrays.  

The easiest way to construct an object array is to use the
\code{numarray.objects.array()} function.  For example:

\begin{verbatim}
  >>> import numarray.objects as obj
  >>> o = obj.array(['S', 'J', 1, 'M'])
  >>> print o
  ['S' 'J' 1 'M']
  >>> print o + o
  ['SS' 'JJ' 2 'MM']
\end{verbatim}

In this example, the array contains 3 Python strings and an integer, but the
array elements can be any Python object.  For each pair of elements, the
\function{add} operator is applied.  For strings, \function{add} is defined as
string concatenation.  For integers, \function{add} is defined as numerical
addition.  For a class object, the \function{__add__} and \function{__radd__}
methods would define the result.

\class{ObjectArray} is defined as a subclass of numarray's structural array
class, \class{NDArray}.  As a result, we can do the usual indexing and slicing:

\begin{verbatim}
  >>> import numarray.objects as obj
  >>> print s[0]
  'S'
  >>> print s[:2]
  ['S' 'J']
  >>> s[:2] = 'changed'
  >>> print s
  ['changed' 'changed' 1 'M']
  >>> a = obj.fromlist(numarray.arange(100), shape=(10,10))
  >>> a[2:5, 2:5]
  ObjectArray([[22, 23, 24],
               [32, 33, 34],
               [42, 43, 44]])
\end{verbatim}

\section{Object array functions}
\label{sec:objectarray-func}
\begin{funcdesc}{array}{sequence=None, shape=None, typecode='O'}
\label{func:obj.array}
   The function \function{array} is, for most practical purposes, all a user needs 
   to know to construct an object array.

   The first argument, \code{sequence}, can be an arbitrary sequence of Python
   objects, such as a list, tuple, or another object array.  

\begin{verbatim}
  >>> import numarray.objects as obj
  >>> class C:
  ...     pass
  >>> c = C()
  >>> a = obj.array([c, c, c])
  >>> a
  ObjectArray([c, c, c])
\end{verbatim}
   
   Like objects in Python lists, objects in object arrays are referred to, not
   copied, so changes to the objects are reflected in the originals because
   they are one and the same.

\begin{verbatim}
     >>> a[0].attribute  = 'this'
     >>> c.attribute
     'this'
\end{verbatim}
   
   The second argument, \code{shape}, optionally specifies the shape of the
   array.  If no \code{shape} is specified, the shape is implied by the
   sequence.

\begin{verbatim}
  >>> import numarray.objects as obj
  >>> class C:
  ...     pass
  >>> c = C()
  >>> a = obj.fromlist([c, c, c])
  >>> a
  ObjectArray([c, c, c])
\end{verbatim}
   
   The last argument, \code{typecode}, is there for backward compatibility with
   Numeric; it must be specified as 'O'.

\end{funcdesc}
   
\begin{funcdesc}{asarray}{obj}
  \label{func:obj.asarray}
  \code{asarray} converts sequences which are not object arrays into object
  arrays.  If \code{obj} is already an \class{ObjectArray}, it is returned
  unaltered.
\begin{verbatim}
  >>> import numarray.objects as obj
  >>> a = obj.asarray([1,''this'',''that''])
  >>> a
  ObjectArray([1 'this' 'that'])
  >>> b = obj.asarray(a)
  >>> b is a
  True
\end{verbatim}
\end{funcdesc}

\begin{funcdesc}{choose}{selector, population, output=None}
  \label{func:obj.choose}
  \code{choose} selects elements from \var{population} based on the values in
  \var{selector}, either returning the selected array or storing it in the
  optional \code{ObjectArray} specified by \var{output}.  \var{selector} should
  be an integer sequence where each element is within the range 0 to
  \function{len}{population}.  \var{population} should be a sequence of
  \class{ObjectArray}s. The shapes of \var{selector} and each element of
  \var{population} must be mutually broadcastable.
\begin{verbatim}
  >>> import numarray.objects as obj
  >>> s = num.arange(25, shape=(5,5)) % 3
  >>> p = obj.fromlist(["foo", 1, {"this":"that"}])
  >>> obj.choose(s, p)
  ObjectArray([['foo', 1, {'this': 'that'}, 'foo', 1],
    [{'this': 'that'}, 'foo', 1, {'this': 'that'}, 'foo'],
    [1, {'this': 'that'}, 'foo', 1, {'this': 'that'}],
    ['foo', 1, {'this': 'that'}, 'foo', 1],
    [{'this': 'that'}, 'foo', 1, {'this': 'that'}, 'foo']])
  
\end{verbatim}
\end{funcdesc}

\begin{funcdesc}{sort}{objects, axis=-1, output=None}
  \label{func:obj.sort}
  \code{sort} sorts the elements from \var{objects} along the specified
  \var{axis}.  If an output array is specified, the result is stored there
  and the return value is None,  otherwise the sort is returned.
\begin{verbatim}
    >>> import numarray.objects as obj
    >>> a = obj.ObjectArray(shape=(5,5))
    >>> a[:] = range(5,0,-1)
    >>> obj.sort(a)
    ObjectArray([[1, 2, 3, 4, 5],
                 [1, 2, 3, 4, 5],
                 [1, 2, 3, 4, 5],
                 [1, 2, 3, 4, 5],
                 [1, 2, 3, 4, 5]])
    >>> a[:] = range(5,0,-1)
    >>> a.transpose()
    >>> obj.sort(a, axis=0)
    ObjectArray([[1, 1, 1, 1, 1],
                 [2, 2, 2, 2, 2],
                 [3, 3, 3, 3, 3],
                 [4, 4, 4, 4, 4],
                 [5, 5, 5, 5, 5]])
\end{verbatim}
\end{funcdesc}

\begin{funcdesc}{argsort}{objects, axis=-1, output=None}
  \label{func:obj.argsort}
  \code{argsort} returns the sort order for the elements from \var{objects}
  along the specified \var{axis}.  If an output array is specified, the result
  is stored there and the return value is None, otherwise the sort order is
  returned.
\begin{verbatim}
  >>> import numarray.objects as obj
  >>> a = obj.ObjectArray(shape=(5,5))
  >>> a[:] = ['e','d','c','b','a']
  >>> obj.argsort(a)
  array([[4, 3, 2, 1, 0],
         [4, 3, 2, 1, 0],
         [4, 3, 2, 1, 0],
         [4, 3, 2, 1, 0],
         [4, 3, 2, 1, 0]])
\end{verbatim}
\end{funcdesc}

\begin{funcdesc}{take}{objects, indices, axis=0}
  \label{func:obj.take}
  \code{take} returns elements of \var{objects} specified by tuple of index
  arrays \var{indices} along the specified \var{axis}.
\begin{verbatim}
  >>> import numarray.objects as obj
  >>> o = obj.fromlist(range(10))
  >>> a = obj.arange(5)*2
  >>> obj.take(o, a)
  ObjectArray([0, 2, 4, 6, 8])
\end{verbatim}
\end{funcdesc}

\begin{funcdesc}{put}{objects, indices, values, axis=-1}
  \label{func:obj.put}
  \function{put} stores \var{values} at the locations of \var{objects}
  specified by tuple of index arrays \var{indices}.
\begin{verbatim}
  >>> import numarray.objects as obj
  >>> o = obj.fromlist(range(10))
  >>> a = obj.arange(5)*2
  >>> obj.put(o, a, 0); o
  ObjectArray([0, 1, 0, 3, 0, 5, 0, 7, 0, 9])
\end{verbatim}
\end{funcdesc}

\begin{funcdesc}{add}{objects1, objects2, out=None}
  \label{func:obj.add}
  \code{numarray.objects} defines universal functions which are named after and
  use the operators defined in the standard library module operator.py.  In
  addition, the operator hooks of the \class{ObjectArray} class are defined to
  call the operators.  \code{add} applies the \code{add} operator to
  corresponding elements of \var{objects1} and \var{objects2}.  Like the ufuncs
  in the numerical side of numarray, the object ufuncs support reduction and
  accumulation.  In addition to add, there are ufuncs defined for every unary
  and binary operator function in the standard library module operator.py.
  Some of these are given additional synonyms so that they use numarray naming
  conventions, e.g. \function{sub} has an alias named \function{subtract}.
\begin{verbatim}
  >>> import numarray.objects as obj
  >>> a = obj.fromlist(["t","u","w"])
  >>> a
  ObjectArray(['t', 'u', 'w'])
  >>> a+a
  ObjectArray(['tt', 'uu', 'ww'])
  >>> obj.add(a,a)
  ObjectArray(['tt', 'uu', 'ww'])
  >>> obj.add.reduce(a)
  'tuw' # not, as in the docs, an ObjectArray
  >>> obj.add.accumulate(a)
  ObjectArray(['t', 'tu', 'tuw']) # w, not v

  >>> a = obj.fromlist(["t","u","w"])
  >>> a
  ObjectArray(['t', 'u', 'w'])
  >>> a+a
  ObjectArray(['tt', 'uu', 'ww'])
  >>> obj.add(a,a)
  ObjectArray(['tt', 'uu', 'ww'])
  >>> obj.add.reduce(a)
  ObjectArray('tuv')
  >>> obj.add.accumulate(a)
  ObjectArray(['t', 'tu', 'tuv'])
\end{verbatim}
\end{funcdesc}

\section{Object array methods}
\label{sec:objectarray-methods}
\class{ObjectArray} maps each of its operator hooks (e.g. \code{__add__}) onto
the corresponding object ufunc (e.g. \code{numarray.objects.add}).  In addition
to its hook methods,  \class{ObjectArray} has these public methods:

\begin{methoddesc}[ObjectArray]{tolist}{}
  \code{tolist} returns a nested list of objects corresponding to all the
  elements in the array.
\end{methoddesc}

\begin{methoddesc}[ObjectArray]{copy}{}
  \code{copy} returns a shallow copy of the object array.
\end{methoddesc}

\begin{methoddesc}[ObjectArray]{astype}{type}
  \code{astype} returns either a copy of the \class{ObjectArray} or converts it
  into a numerical array of the specified \var{type}.
\end{methoddesc}

\begin{methoddesc}[ObjectArray]{info}{}
   This will display key attributes of the object array.
\end{methoddesc}

%% Local Variables:
%% mode: LaTeX
%% mode: auto-fill
%% fill-column: 79
%% indent-tabs-mode: nil
%% ispell-dictionary: "american"
%% reftex-fref-is-default: nil
%% TeX-auto-save: t
%% TeX-command-default: "pdfeLaTeX"
%% TeX-master: "numarray"
%% TeX-parse-self: t
%% End:
