Normalize collection arguments to eliminate overlapping paths and parts. Detects when collection arguments overlap in either paths or parts and only keeps the shorter prefix, or the earliest argument if duplicate, preserving order. The result is prefix-free.
(
collection_args: Sequence[CollectionArgument],
)
| 1188 | |
| 1189 | |
| 1190 | def normalize_collection_arguments( |
| 1191 | collection_args: Sequence[CollectionArgument], |
| 1192 | ) -> list[CollectionArgument]: |
| 1193 | """Normalize collection arguments to eliminate overlapping paths and parts. |
| 1194 | |
| 1195 | Detects when collection arguments overlap in either paths or parts and only |
| 1196 | keeps the shorter prefix, or the earliest argument if duplicate, preserving |
| 1197 | order. The result is prefix-free. |
| 1198 | """ |
| 1199 | # A quadratic algorithm is not acceptable since large inputs are possible. |
| 1200 | # So this uses an O(n*log(n)) algorithm which takes advantage of the |
| 1201 | # property that after sorting, a collection argument will immediately |
| 1202 | # precede collection arguments it subsumes. An O(n) algorithm is not worth |
| 1203 | # it. |
| 1204 | collection_args_sorted = sorted( |
| 1205 | collection_args, |
| 1206 | key=lambda arg: (arg.path, arg.parts, arg.parametrization or ""), |
| 1207 | ) |
| 1208 | normalized: list[CollectionArgument] = [] |
| 1209 | last_kept = None |
| 1210 | for arg in collection_args_sorted: |
| 1211 | if last_kept is None or not is_collection_argument_subsumed_by(arg, last_kept): |
| 1212 | normalized.append(arg) |
| 1213 | last_kept = arg |
| 1214 | normalized.sort(key=lambda arg: arg.original_index) |
| 1215 | return normalized |
no test coverage detected