Completed
Push — develop ( 3d94e8...e1a83c )
by Kale
01:01
created

first()   B

Complexity

Conditions 5

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 5
c 1
b 0
f 1
dl 0
loc 31
rs 8.0894
1
# -*- coding: utf-8 -*-
2
"""Common collection classes."""
3
from __future__ import print_function, division, absolute_import
4
5
6
# http://stackoverflow.com/a/14620633/2127762
7
class AttrDict(dict):
8
    """Sub-classes dict, and further allows attribute-like access to dictionary items.
9
10
    Examples:
11
        >>> d = AttrDict({'a': 1})
12
        >>> d.a, d['a'], d.get('a')
13
        (1, 1, 1)
14
        >>> d.b = 2
15
        >>> d.b, d['b']
16
        (2, 2)
17
    """
18
    def __init__(self, *args, **kwargs):
19
        super(AttrDict, self).__init__(*args, **kwargs)
20
        self.__dict__ = self
21
22
23
def first(seq, key=lambda x: bool(x), default=None, apply=lambda x: x):
24
    """Give the first value that satisfies the key test.
25
26
    Args:
27
        seq (iterable):
28
        key (callable): test for each element of iterable
29
        default: returned when all elements fail test
30
        apply (callable): applied to element before return
31
32
    Returns: first element in seq that passes key, mutated with optional apply
33
34
    Examples:
35
        >>> first([0, False, None, [], (), 42])
36
        42
37
        >>> first([0, False, None, [], ()]) is None
38
        True
39
        >>> first([0, False, None, [], ()], default='ohai')
40
        'ohai'
41
        >>> import re
42
        >>> m = first(re.match(regex, 'abc') for regex in ['b.*', 'a(.*)'])
43
        >>> m.group(1)
44
        'bc'
45
46
        The optional `key` argument specifies a one-argument predicate function
47
        like that used for `filter()`.  The `key` argument, if supplied, must be
48
        in keyword form.  For example:
49
        >>> first([1, 1, 3, 4, 5], key=lambda x: x % 2 == 0)
50
        4
51
52
    """
53
    return next((apply(x) for x in seq if key(x)), default)
54
55
56
def cumulative_first(seq, key=lambda x: bool(x), apply=lambda x: x):
57
    """like first, but cumulative, up to and including first
58
59
    unlike first, there is no default; where default would be returned in first, all of seq is
60
    returned in cumulative_first
61
62
    Args:
63
        seq (iterable):
64
        key (callable): test for each element of seq
65
        apply (callable): applied to each element before return
66
67
    Examples:
68
        >>> cumulative_first([0, False, None, [], (), 42])
69
        (0, False, None, [], (), 42)
70
        >>> cumulative_first([0, False, 'some', [], (), 42])
71
        (0, False, 'some')
72
73
    """
74
    lst = []
75
    for element in seq:
76
        lst.append(apply(element))
77
        if key(element):
78
            break
79
    return tuple(lst)
80
81
82
def last(seq, key=lambda x: bool(x), default=None, apply=lambda x: x):
83
    return next((apply(x) for x in reversed(seq) if key(x)), default)
84
85