11
11
from .merge import _align_for_merge as deep_align
12
12
from .merge import merge_coords_without_align
13
13
from .utils import is_dict_like
14
- from .pycompat import dask_array_type , OrderedDict , basestring
14
+ from .pycompat import dask_array_type , OrderedDict , basestring , suppress
15
15
16
16
17
17
SLICE_NONE = slice (None )
@@ -138,22 +138,41 @@ def _default_result_attrs(attrs, func, signature):
138
138
139
139
140
140
def build_output_coords (args , signature , new_coords = None ):
141
+ coord_variables = []
142
+ for arg in args :
143
+ try :
144
+ coords = arg .coords
145
+ except AttributeError :
146
+ pass # skip this argument
147
+ else :
148
+ coord_vars = getattr (coords , 'variables' , coords )
149
+ coord_variables .append (coord_vars )
141
150
142
- coord_variables = [getattr (getattr (arg , 'coords' , {}), 'variables' , {})
143
- for arg in args ]
144
151
if new_coords is not None :
145
152
coord_variables .append (getattr (new_coords , 'variables' , new_coords ))
146
153
147
- merged = merge_coords_without_align (coord_variables )
154
+ if len (args ) == 1 and new_coords is None :
155
+ # we can skip the expensive merge
156
+ merged , = coord_variables
157
+ else :
158
+ merged = merge_coords_without_align (coord_variables )
159
+
160
+ missing_dims = signature .all_output_core_dims - set (merged )
161
+ if missing_dims :
162
+ raise ValueError ('new output dimensions must have matching entries in '
163
+ '`new_coords`: %r' % missing_dims )
148
164
149
- output = []
165
+ output_coords = []
150
166
for output_dims in signature .output_core_dims :
151
167
dropped_dims = signature .all_input_core_dims - set (output_dims )
152
- coords = OrderedDict ((k , v ) for k , v in merged .items ()
153
- if set (v .dims ).isdisjoint (dropped_dims ))
154
- output .append (coords )
168
+ if dropped_dims :
169
+ coords = OrderedDict ((k , v ) for k , v in merged .items ()
170
+ if set (v .dims ).isdisjoint (dropped_dims ))
171
+ else :
172
+ coords = merged
173
+ output_coords .append (coords )
155
174
156
- return output
175
+ return output_coords
157
176
158
177
159
178
def apply_dataarray_ufunc (func , * args , ** kwargs ):
@@ -172,7 +191,8 @@ def apply_dataarray_ufunc(func, *args, **kwargs):
172
191
if signature is None :
173
192
signature = _default_signature (len (args ))
174
193
175
- args = deep_align (args , join = join , copy = False , raise_on_invalid = False )
194
+ if len (args ) > 1 :
195
+ args = deep_align (args , join = join , copy = False , raise_on_invalid = False )
176
196
177
197
name = result_name (args )
178
198
result_coords = build_output_coords (args , signature , new_coords )
@@ -181,16 +201,23 @@ def apply_dataarray_ufunc(func, *args, **kwargs):
181
201
result_var = func (* data_vars )
182
202
183
203
if signature .n_outputs > 1 :
184
- return tuple (DataArray (variable , coords , name = name )
204
+ return tuple (DataArray (variable , coords , name = name , fastpath = True )
185
205
for variable , coords in zip (result_var , result_coords ))
186
206
else :
187
207
coords , = result_coords
188
- return DataArray (result_var , coords , name = name )
208
+ return DataArray (result_var , coords , name = name , fastpath = True )
189
209
190
210
191
211
def join_dict_keys (objects , how = 'inner' ):
212
+ all_keys = [obj .keys () for obj in objects if hasattr (obj , 'keys' )]
213
+
214
+ if len (all_keys ) == 1 :
215
+ # shortcut
216
+ result_keys , = all_keys
217
+ return result_keys
218
+
192
219
joiner = _get_joiner (how )
193
- all_keys = ( obj . keys () for obj in objects if hasattr ( obj , 'keys' ))
220
+ # TODO: use a faster ordered set than a pandas.Index
194
221
result_keys = joiner ([pd .Index (keys ) for keys in all_keys ])
195
222
return result_keys
196
223
@@ -203,6 +230,17 @@ def collect_dict_values(objects, keys, fill_value=None):
203
230
for key in keys ]
204
231
205
232
233
+ def _fast_dataset (variables , coord_variables ):
234
+ """Create a dataset as quickly as possible.
235
+
236
+ Variables are modified *inplace*.
237
+ """
238
+ from .dataset import Dataset
239
+ variables .update (coord_variables )
240
+ coord_names = set (coord_variables )
241
+ return Dataset ._from_vars_and_coord_names (variables , coord_names )
242
+
243
+
206
244
def apply_dataset_ufunc (func , * args , ** kwargs ):
207
245
"""
208
246
def apply_dataset_ufunc(func, args, signature=None, join='inner',
@@ -221,7 +259,8 @@ def apply_dataset_ufunc(func, args, signature=None, join='inner',
221
259
if signature is None :
222
260
signature = _default_signature (len (args ))
223
261
224
- args = deep_align (args , join = join , copy = False , raise_on_invalid = False )
262
+ if len (args ) > 1 :
263
+ args = deep_align (args , join = join , copy = False , raise_on_invalid = False )
225
264
226
265
list_of_coords = build_output_coords (args , signature , new_coords )
227
266
@@ -243,12 +282,11 @@ def apply_dataset_ufunc(func, args, signature=None, join='inner',
243
282
for value , results_dict in zip (values , result_dict_list ):
244
283
results_dict [name ] = value
245
284
246
- return tuple (Dataset (* args )
285
+ return tuple (_fast_dataset (* args )
247
286
for args in zip (result_dict_list , list_of_coords ))
248
287
else :
249
- data_vars = result_vars
250
288
coord_vars , = list_of_coords
251
- return Dataset ( data_vars , coord_vars )
289
+ return _fast_dataset ( result_vars , coord_vars )
252
290
253
291
254
292
def _iter_over_selections (obj , dim , values ):
0 commit comments