Skip to content

Commit 0cd2dee

Browse files
committed
array2d_to_array1d now supports 1d arrays
1 parent 8e7937f commit 0cd2dee

File tree

2 files changed

+62
-18
lines changed

2 files changed

+62
-18
lines changed

src/_arraykit.c

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3528,12 +3528,16 @@ array_deepcopy(PyObject *m, PyObject *args, PyObject *kwargs)
35283528
static PyObject *
35293529
array2d_to_array1d(PyObject *Py_UNUSED(m), PyObject *a)
35303530
{
3531-
AK_CHECK_NUMPY_ARRAY_2D(a);
3531+
AK_CHECK_NUMPY_ARRAY(a);
35323532
PyArrayObject *input_array = (PyArrayObject *)a;
3533+
int ndim = PyArray_NDIM(input_array);
3534+
if (ndim != 1 && ndim != 2) {
3535+
return PyErr_Format(PyExc_NotImplementedError,
3536+
"Expected 1D or 2D array, not %i.",
3537+
ndim);
3538+
}
35333539

35343540
npy_intp num_rows = PyArray_DIM(input_array, 0);
3535-
npy_intp num_cols = PyArray_DIM(input_array, 1);
3536-
35373541
npy_intp dims[] = {num_rows};
35383542
// NOTE: this initializes values to NULL, not None
35393543
PyObject* output = PyArray_SimpleNew(1, dims, NPY_OBJECT);
@@ -3545,26 +3549,46 @@ array2d_to_array1d(PyObject *Py_UNUSED(m), PyObject *a)
35453549
PyObject** p = output_data;
35463550
PyObject** p_end = p + num_rows;
35473551
npy_intp i = 0;
3548-
npy_intp j;
35493552
PyObject* tuple;
35503553
PyObject* item;
35513554

3552-
while (p < p_end) {
3553-
tuple = PyTuple_New(num_cols);
3554-
if (tuple == NULL) {
3555-
goto error;
3555+
if (ndim == 2) {
3556+
npy_intp num_cols = PyArray_DIM(input_array, 1);
3557+
npy_intp j;
3558+
while (p < p_end) {
3559+
tuple = PyTuple_New(num_cols);
3560+
if (tuple == NULL) {
3561+
goto error;
3562+
}
3563+
for (j = 0; j < num_cols; ++j) {
3564+
// cannot assume input_array is contiguous
3565+
item = PyArray_ToScalar(PyArray_GETPTR2(input_array, i, j), input_array);
3566+
if (item == NULL) {
3567+
Py_DECREF(tuple);
3568+
goto error;
3569+
}
3570+
PyTuple_SET_ITEM(tuple, j, item); // steals reference to item
3571+
}
3572+
*p++ = tuple; // assign with new ref, no incr needed
3573+
i++;
35563574
}
3557-
for (j = 0; j < num_cols; ++j) {
3558-
// cannot assume input_array is contiguous
3559-
item = PyArray_ToScalar(PyArray_GETPTR2(input_array, i, j), input_array);
3575+
}
3576+
else { // ndim == 1
3577+
while (p < p_end) {
3578+
tuple = PyTuple_New(1);
3579+
if (tuple == NULL) {
3580+
goto error;
3581+
}
3582+
// scalar returned in is native PyObject from object arrays
3583+
item = PyArray_ToScalar(PyArray_GETPTR1(input_array, i), input_array);
35603584
if (item == NULL) {
35613585
Py_DECREF(tuple);
35623586
goto error;
35633587
}
3564-
PyTuple_SET_ITEM(tuple, j, item); // steals reference to item
3588+
PyTuple_SET_ITEM(tuple, 0, item); // steals reference to item
3589+
*p++ = tuple; // assign with new ref, no incr needed
3590+
i++;
35653591
}
3566-
*p++ = tuple; // assign with new ref, no incr needed
3567-
i++;
35683592
}
35693593
PyArray_CLEARFLAGS((PyArrayObject *)output, NPY_ARRAY_WRITEABLE);
35703594
return output;

test/test_util.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,31 @@ def test_array_deepcopy_h(self) -> None:
286286
a2 = array_deepcopy(a1, ())
287287

288288
#---------------------------------------------------------------------------
289-
def test_array2d_to_array1d_dummy(self) -> None:
289+
def test_array2d_to_array1d_1d_a(self) -> None:
290290
a1 = np.arange(10)
291-
with self.assertRaises(NotImplementedError):
292-
# 1 dimensional
293-
_ = array2d_to_array1d(a1)
291+
a2 = array2d_to_array1d(a1)
292+
self.assertEqual(a2.tolist(), [(0,), (1,), (2,), (3,), (4,), (5,), (6,), (7,), (8,), (9,)])
293+
294+
def test_array2d_to_array1d_1d_b(self) -> None:
295+
a1 = np.array(['aaa', 'b', 'ccc'])
296+
a2 = array2d_to_array1d(a1)
297+
self.assertEqual(a2.tolist(), [('aaa',), ('b',), ('ccc',)])
298+
299+
def test_array2d_to_array1d_1d_c(self) -> None:
300+
a1 = np.array([None, 'b', 30])
301+
a2 = array2d_to_array1d(a1)
302+
self.assertEqual(a2.tolist(), [(None,), ('b',), (30,)])
303+
304+
def test_array2d_to_array1d_1d_d(self) -> None:
305+
a1 = np.array([('a', 10), ('b', 30), ('c', 5)], dtype=object)
306+
a2 = array2d_to_array1d(a1)
307+
self.assertEqual(a2.tolist(), [('a', 10), ('b', 30), ('c', 5)])
308+
309+
def test_array2d_to_array1d_1d_e(self) -> None:
310+
a1 = np.array([True, False, True], dtype=object)
311+
a2 = array2d_to_array1d(a1)
312+
self.assertIs(a2[0][0].__class__, bool)
313+
self.assertEqual(a2.tolist(), [(True,), (False,), (True,)])
294314

295315
def test_array2d_to_array1d_b(self) -> None:
296316
a1 = np.arange(10, dtype=np.int64).reshape(5, 2)

0 commit comments

Comments
 (0)