Returns all possible variations of a sequence with optional items.
(iterable, optional=lambda x: False)
| 145 | pass |
| 146 | |
| 147 | def variations(iterable, optional=lambda x: False): |
| 148 | """ Returns all possible variations of a sequence with optional items. |
| 149 | """ |
| 150 | # For example: variations(["A?", "B?", "C"], optional=lambda s: s.endswith("?")) |
| 151 | # defines a sequence where constraint A and B are optional: |
| 152 | # [("A?", "B?", "C"), ("B?", "C"), ("A?", "C"), ("C")] |
| 153 | iterable = tuple(iterable) |
| 154 | # Create a boolean sequence where True means optional: |
| 155 | # ("A?", "B?", "C") => [True, True, False] |
| 156 | o = [optional(x) for x in iterable] |
| 157 | # Find all permutations of the boolean sequence: |
| 158 | # [True, False, True], [True, False, False], [False, False, True], [False, False, False]. |
| 159 | # Map to sequences of constraints whose index in the boolean sequence yields True. |
| 160 | a = set() |
| 161 | for p in product([False, True], repeat=sum(o)): |
| 162 | p = list(p) |
| 163 | v = [b and (b and p.pop(0)) for b in o] |
| 164 | v = tuple(iterable[i] for i in range(len(v)) if not v[i]) |
| 165 | if v not in a: |
| 166 | a.add(v) |
| 167 | # Longest-first. |
| 168 | return sorted(a, cmp=lambda x, y: len(y) - len(x)) |
| 169 | |
| 170 | #### TAXONOMY ###################################################################################### |
| 171 |