1313
1414
1515@high_level_function ()
16- def unzip (array , * , highlevel = True , behavior = None , attrs = None ):
16+ def unzip (
17+ array ,
18+ * ,
19+ how = tuple ,
20+ highlevel = True ,
21+ behavior = None ,
22+ attrs = None ,
23+ ):
1724 """
1825 Args:
1926 array: Array-like data (anything #ak.to_layout recognizes).
27+ how (type): The type of the returned output. This can be `tuple` or `dict`.
2028 highlevel (bool): If True, return an #ak.Array; otherwise, return
2129 a low-level #ak.contents.Content subclass.
2230 behavior (None or dict): Custom #ak.behavior for the output array, if
@@ -25,10 +33,10 @@ def unzip(array, *, highlevel=True, behavior=None, attrs=None):
2533 high-level.
2634
2735 If the `array` contains tuples or records, this operation splits them
28- into a Python tuple of arrays, one for each field.
36+ into a Python tuple (or dict) of arrays, one for each field.
2937
3038 If the `array` does not contain tuples or records, the single `array`
31- is placed in a length 1 Python tuple.
39+ is placed in a length 1 Python tuple (or dict) .
3240
3341 For example,
3442
@@ -40,15 +48,32 @@ def unzip(array, *, highlevel=True, behavior=None, attrs=None):
4048 <Array [1.1, 2.2, 3.3] type='3 * float64'>
4149 >>> y
4250 <Array [[1], [2, 2], [3, 3, 3]] type='3 * var * int64'>
51+
52+ The `how` argument determines the structure of the output. Using `how=dict`
53+ returns a dictionary of arrays instead of a tuple, and let's you round-trip
54+ through `ak.zip`:
55+
56+ >>> array = ak.Array([{"x": 1.1, "y": [1]},
57+ ... {"x": 2.2, "y": [2, 2]},
58+ ... {"x": 3.3, "y": [3, 3, 3]}])
59+ >>> x = ak.unzip(array, how=dict)
60+ >>> x
61+ {'x': <Array [1.1, 2.2, 3.3] type='3 * float64'>,
62+ 'y': <Array [[1], [2, 2], [3, 3, 3]] type='3 * var * int64'>}
63+ >>> assert ak.zip(ak.unzip(array, how=dict), depth_limit=1).to_list() == array.to_list() # True
64+
4365 """
4466 # Dispatch
4567 yield (array ,)
4668
4769 # Implementation
48- return _impl (array , highlevel , behavior , attrs )
70+ return _impl (array , how , highlevel , behavior , attrs )
71+
4972
73+ def _impl (array , how , highlevel , behavior , attrs ):
74+ if how not in {tuple , dict }:
75+ raise ValueError (f"`how` must be `tuple` or `dict`, not { how !r} " )
5076
51- def _impl (array , highlevel , behavior , attrs ):
5277 with HighLevelContext (behavior = behavior , attrs = attrs ) as ctx :
5378 layout = ctx .unwrap (array , allow_record = True , primitive_policy = "error" )
5479
@@ -68,13 +93,10 @@ def check_for_union(layout, **kwargs):
6893 ak ._do .recursively_apply (layout , check_for_union , return_array = False )
6994
7095 if len (fields ) == 0 :
71- return (ctx .wrap (layout , highlevel = highlevel , allow_other = True ),)
96+ items = (ctx .wrap (layout , highlevel = highlevel , allow_other = True ),)
97+ fields = ["0" ]
7298 else :
73- return tuple (
74- ctx .wrap (
75- layout [n ],
76- highlevel = highlevel ,
77- allow_other = True ,
78- )
79- for n in fields
99+ items = (
100+ ctx .wrap (layout [n ], highlevel = highlevel , allow_other = True ) for n in fields
80101 )
102+ return tuple (items ) if how is tuple else dict (zip (fields , items ))
0 commit comments