22
33__all__ = ['defaults' , 'copy_func' , 'patch_to' , 'patch' , 'patch_property' , 'add_docs' , 'docs' , 'custom_dir' , 'arg0' ,
44 'arg1' , 'arg2' , 'arg3' , 'arg4' , 'coll_repr' , 'is_bool' , 'mask2idxs' , 'cycle' , 'zip_cycle' , 'is_indexer' ,
5- 'negate_func' , 'GetAttr' , 'delegate_attr' , 'bind' , 'listable_types' , 'CollBase' , 'L' ]
5+ 'negate_func' , 'GetAttr' , 'delegate_attr' , 'bind' , 'listable_types' , 'first' , ' CollBase' , 'L' ]
66
77# Cell
88from .imports import *
@@ -181,6 +181,12 @@ def __call__(self, *args, **kwargs):
181181# Cell
182182listable_types = typing .Collection ,Generator ,map ,filter ,zip
183183
184+ # Cell
185+ def first (x ):
186+ "First element of `x`, or None if missing"
187+ try : return next (iter (x ))
188+ except StopIteration : return None
189+
184190# Cell
185191class CollBase :
186192 "Base class for composing a list of `items`"
@@ -265,16 +271,20 @@ def range(cls, a, b=None, step=None):
265271 if is_coll (a ): a = len (a )
266272 return cls (range (a ,b ,step ) if step is not None else range (a ,b ) if b is not None else range (a ))
267273
268- def map (self , f , * args , ** kwargs ):
274+ def map (self , f , * args , gen = False , ** kwargs ):
269275 g = (bind (f ,* args ,** kwargs ) if callable (f )
270276 else f .format if isinstance (f ,str )
271277 else f .__getitem__ )
272- return self ._new (map (g , self ))
278+ res = map (g , self )
279+ if gen : return res
280+ return self ._new (res )
273281
274- def filter (self , f , negate = False , ** kwargs ):
282+ def filter (self , f = noop , negate = False , gen = False , ** kwargs ):
275283 if kwargs : f = partial (f ,** kwargs )
276284 if negate : f = negate_func (f )
277- return self ._new (filter (f , self ))
285+ res = filter (f , self )
286+ if gen : return res
287+ return self ._new (res )
278288
279289 def argwhere (self , f , negate = False , ** kwargs ):
280290 if kwargs : f = partial (f ,** kwargs )
@@ -291,7 +301,13 @@ def itemgot(self, *idxs):
291301
292302 def attrgot (self , k , default = None ): return self .map (lambda o : o .get (k ,default ) if isinstance (o , dict ) else getattr (o ,k ,default ))
293303 def cycle (self ): return cycle (self )
294- def map_dict (self , f = noop , * args , ** kwargs ): return {k :f (k , * args ,** kwargs ) for k in self }
304+ def map_dict (self , f = noop , * args , gen = False , ** kwargs ): return {k :f (k , * args ,** kwargs ) for k in self }
305+ def map_filter (self , f = noop , g = noop , * args , gen = False , ** kwargs ):
306+ res = filter (g , self .map (f , * args , gen = gen , ** kwargs ))
307+ if gen : return res
308+ return self ._new (res )
309+ def map_first (self , f = noop , g = noop , * args , ** kwargs ): return first (self .map_filter (f , g , * args , gen = False , ** kwargs ))
310+
295311 def starmap (self , f , * args , ** kwargs ): return self ._new (itertools .starmap (partial (f ,* args ,** kwargs ), self ))
296312 def zip (self , cycled = False ): return self ._new ((zip_cycle if cycled else zip )(* self ))
297313 def zipwith (self , * rest , cycled = False ): return self ._new ([self , * rest ]).zip (cycled = cycled )
@@ -329,6 +345,8 @@ def product(self): return self.reduce(operator.mul)
329345 filter = "Create new `L` filtered by predicate `f`, passing `args` and `kwargs` to `f`" ,
330346 argwhere = "Like `filter`, but return indices for matching items" ,
331347 map = "Create new `L` with `f` applied to all `items`, passing `args` and `kwargs` to `f`" ,
348+ map_filter = "Same as `map` with `f` followed by `filter` with `g`" ,
349+ map_first = "First element of `map_filter`" ,
332350 map_dict = "Like `map`, but creates a dict from `items` to function results" ,
333351 starmap = "Like `map`, but use `itertools.starmap`" ,
334352 itemgot = "Create new `L` with item `idx` of all `items`" ,
0 commit comments