|
6 | 6 | 'AttrDict', 'with_cast', 'store_attr', 'attrdict', 'properties', 'camel2snake', 'snake2camel', 'class2attr', |
7 | 7 | 'hasattrs', 'setattrs', 'try_attrs', 'ShowPrint', 'Int', 'Str', 'Float', 'detuplify', 'replicate', 'setify', |
8 | 8 | 'merge', 'range_of', 'groupby', 'last_index', 'filter_dict', 'filter_keys', 'filter_values', 'cycle', |
9 | | - 'zip_cycle', 'sorted_ex', 'num_methods', 'rnum_methods', 'inum_methods', 'fastuple', 'compose', 'maps', |
10 | | - 'partialler', 'instantiate', 'using_attr', 'Self', 'Self', 'PrettyString', 'even_mults', 'num_cpus', |
11 | | - 'add_props', 'typed'] |
| 9 | + 'zip_cycle', 'sorted_ex', 'negate_func', 'argwhere', 'filter_ex', 'range_of', 'renumerate', 'first', |
| 10 | + 'nested_attr', 'nested_idx', 'num_methods', 'rnum_methods', 'inum_methods', 'fastuple', 'arg0', 'arg1', |
| 11 | + 'arg2', 'arg3', 'arg4', 'bind', 'map_ex', 'compose', 'maps', 'partialler', 'instantiate', 'using_attr', |
| 12 | + 'Self', 'Self', 'PrettyString', 'even_mults', 'num_cpus', 'add_props', 'typed'] |
12 | 13 |
|
13 | 14 | # Cell |
14 | 15 | from .imports import * |
@@ -364,6 +365,61 @@ def sorted_ex(iterable, key=None, reverse=False): |
364 | 365 | else: k=key |
365 | 366 | return sorted(iterable, key=k, reverse=reverse) |
366 | 367 |
|
| 368 | +# Cell |
| 369 | +def negate_func(f): |
| 370 | + "Create new function that negates result of `f`" |
| 371 | + def _f(*args, **kwargs): return not f(*args, **kwargs) |
| 372 | + return _f |
| 373 | + |
| 374 | +# Cell |
| 375 | +def argwhere(iterable, f, negate=False, **kwargs): |
| 376 | + "Like `filter_ex`, but return indices for matching items" |
| 377 | + if kwargs: f = partial(f,**kwargs) |
| 378 | + if negate: f = negate_func(f) |
| 379 | + return [i for i,o in enumerate(iterable) if f(o)] |
| 380 | + |
| 381 | +# Cell |
| 382 | +def filter_ex(iterable, f=noop, negate=False, gen=False, **kwargs): |
| 383 | + "Like `filter`, but passing `kwargs` to `f`, defaulting `f` to `noop`, and adding `negate` and `gen`" |
| 384 | + if kwargs: f = partial(f,**kwargs) |
| 385 | + if negate: f = negate_func(f) |
| 386 | + res = filter(f, iterable) |
| 387 | + if gen: return res |
| 388 | + return list(res) |
| 389 | + |
| 390 | +# Cell |
| 391 | +def range_of(a, b=None, step=None): |
| 392 | + "All indices of collection `a`, if `a` is a collection, otherwise `range`" |
| 393 | + if is_coll(a): a = len(a) |
| 394 | + return list(range(a,b,step) if step is not None else range(a,b) if b is not None else range(a)) |
| 395 | + |
| 396 | +# Cell |
| 397 | +def renumerate(iterable, start=0): |
| 398 | + "Same as `enumerate`, but returns index as 2nd element instead of 1st" |
| 399 | + return ((o,i) for i,o in enumerate(iterable, start=start)) |
| 400 | + |
| 401 | +# Cell |
| 402 | +def first(x): |
| 403 | + "First element of `x`, or None if missing" |
| 404 | + try: return next(iter(x)) |
| 405 | + except StopIteration: return None |
| 406 | + |
| 407 | +# Cell |
| 408 | +def nested_attr(o, attr, default=None): |
| 409 | + "Same as `getattr`, but if `attr` includes a `.`, then looks inside nested objects" |
| 410 | + try: |
| 411 | + for a in attr.split("."): o = getattr(o, a) |
| 412 | + except AttributeError: return default |
| 413 | + return o |
| 414 | + |
| 415 | +# Cell |
| 416 | +def nested_idx(coll, *idxs): |
| 417 | + "Index into nested collections, dicts, etc, with `idxs`" |
| 418 | + if not coll or not idxs: return coll |
| 419 | + if isinstance(coll,str) or not isinstance(coll, typing.Collection): return None |
| 420 | + res = coll.get(idxs[0], None) if hasattr(coll, 'get') else coll[idxs[0]] if idxs[0]<len(coll) else None |
| 421 | + return nested_idx(res, *idxs[1:]) |
| 422 | + |
367 | 423 | # Cell |
368 | 424 | num_methods = """ |
369 | 425 | __add__ __sub__ __mul__ __matmul__ __truediv__ __floordiv__ __mod__ __divmod__ __pow__ |
@@ -415,6 +471,40 @@ def _f(self,*args): return self._op(op,*args) |
415 | 471 | setattr(fastuple,'max',_get_op(max)) |
416 | 472 | setattr(fastuple,'min',_get_op(min)) |
417 | 473 |
|
| 474 | +# Cell |
| 475 | +class _Arg: |
| 476 | + def __init__(self,i): self.i = i |
| 477 | +arg0 = _Arg(0) |
| 478 | +arg1 = _Arg(1) |
| 479 | +arg2 = _Arg(2) |
| 480 | +arg3 = _Arg(3) |
| 481 | +arg4 = _Arg(4) |
| 482 | + |
| 483 | +# Cell |
| 484 | +class bind: |
| 485 | + "Same as `partial`, except you can use `arg0` `arg1` etc param placeholders" |
| 486 | + def __init__(self, fn, *pargs, **pkwargs): |
| 487 | + self.fn,self.pargs,self.pkwargs = fn,pargs,pkwargs |
| 488 | + self.maxi = max((x.i for x in pargs if isinstance(x, _Arg)), default=-1) |
| 489 | + |
| 490 | + def __call__(self, *args, **kwargs): |
| 491 | + args = list(args) |
| 492 | + kwargs = {**self.pkwargs,**kwargs} |
| 493 | + for k,v in kwargs.items(): |
| 494 | + if isinstance(v,_Arg): kwargs[k] = args.pop(v.i) |
| 495 | + fargs = [args[x.i] if isinstance(x, _Arg) else x for x in self.pargs] + args[self.maxi+1:] |
| 496 | + return self.fn(*fargs, **kwargs) |
| 497 | + |
| 498 | +# Cell |
| 499 | +def map_ex(iterable, f, *args, gen=False, **kwargs): |
| 500 | + "Like `map`, but use `bind`, and supports `str` and indexing" |
| 501 | + g = (bind(f,*args,**kwargs) if callable(f) |
| 502 | + else f.format if isinstance(f,str) |
| 503 | + else f.__getitem__) |
| 504 | + res = map(g, iterable) |
| 505 | + if gen: return res |
| 506 | + return list(res) |
| 507 | + |
418 | 508 | # Cell |
419 | 509 | def compose(*funcs, order=None): |
420 | 510 | "Create a function that composes all functions in `funcs`, passing along remaining `*args` and `**kwargs` to all" |
|
0 commit comments