News for hackers. Stuff that matters.
Re:Help us collect modern Python NumPy code solutions by m00dy on Monday March 28, 2022 @07:38AM (#30829394)
#write a function that zips numpy arrays

import numpy as np

   def zip_arrays(arrays):

       return np.array([np.concatenate(arr) for arr in zip(*arrays)])
Re:Help us collect modern Python NumPy code solutions by PartiallyTyped on Monday March 28, 2022 @08:17AM (#30829665)
>>> arrays = [np.arange(1000)]*10

>>> zip_arrays(arrays)

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

  File "<stdin>", line 2, in zip_arrays2

  File "<stdin>", line 2, in <listcomp>

  File "<__array_function__ internals>", line 180, in concatenate
ValueError: zero-dimensional arrays cannot be concatenated

Try this:

def zip_arrays(arrays):

    return np.concatenate([array[:l,...,None] for l in [min(array.shape[0] for array in arrays)] for array in arrays], axis=-1)
Or if we are trying to be more tidy instead of a one liner

def zip_arrays(arrays):

    l = min(a.shape[0] for a in arrays)

    arrays = [a[:l, ..., None] for a in arrays]

    return np.concatenate(arrays)
Re:Help us collect modern Python NumPy code solutions by johndough on Monday March 28, 2022 @08:47AM (#30829948)
I think a more Pythonic solution would be

    np.array(arrays).T
or maybe

    np.copy(arrays).T
for one less character. The shortest solution is probably

    np.c_[arrays].T
but likely causes a Google search on first read.
Re:Help us collect modern Python NumPy code solutions by PartiallyTyped on Monday March 28, 2022 @09:53AM (#30830475)
That does not zip though. In fact, it creates a 1-dimensional array of objects because the arrays do not have the same number of items.

     >>> a = [np.arange(i) for i in range(1, 11)]

     >>> np.array(a).T

        array([array([0]), array([0, 1]), array([0, 1, 2]), array([0, 1, 2, 3]),

        array([0, 1, 2, 3, 4]), array([0, 1, 2, 3, 4, 5]),

        array([0, 1, 2, 3, 4, 5, 6]), array([0, 1, 2, 3, 4, 5, 6, 7]),

        array([0, 1, 2, 3, 4, 5, 6, 7, 8]),

        array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])], dtype=object)
In fact, if we are to zip them, it should yield:

>>> list(zip(*a))

[(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)]

zip_arrays otoh does give the same result.

>>> zip_arrays(a)

array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

Re:Help us collect modern Python NumPy code solutions by johndough on Monday March 28, 2022 @10:32AM (#30830883)
You are completely right. Nevertheless, when I zip over arrays of different length, it is usually a bug instead of being intentional.

A code-golfed version for different array lengths:

    np.c_[[a[:min(map(len,arrays))].T for a in arrays]].T
The trick to get a local variable within a list comprehension statement with

    for l in [foo()]
from your zip_array function is very cool by the way, but I sacrificed it in favor of shorter code.
Re:Help us collect modern Python NumPy code solutions by PartiallyTyped on Monday March 28, 2022 @01:15PM (#30832905)
I like your your solution, I think using `a[0:min(map(len,arrays))]` (ie with 0) is faster because it returns a slice and not a copy of the array.

I am glad you liked the trick!

Re:Help us collect modern Python NumPy code solutions by kzrdude on Monday March 28, 2022 @01:01PM (#30832705)
I'm used to numpy and I can't understand np.c_ even with the docs. It says "Translates slice objects to concatenation along the second axis." but the examples pass in a list of arrays and use no slice objects (the builtin slice, I'm assuming)?

If there was an example using just `np.c_[1:5, 11:15]` it would make sense. But clearly np.c_'s meaning has been extended beyond slices in some way. (Maybe I'm coming closer to understanding, but still miffed about the misleading doc.)

Re:Help us collect modern Python NumPy code solutions by m00dy on Monday March 28, 2022 @09:06AM (#30830128)
well, I used the code from Copilot :)