Commits
Vincent Geers authored fb8b0517db1 Merge
4224 4224 | return_dict : boolean : OPTIONAL |
4225 4225 | If set to True, then a dictionary is returned with the correct syntax |
4226 4226 | to fill the excludechan parameter of the self.renormalize() method. |
4227 4227 | Default: False |
4228 4228 | NOTE: This takes priority over return_command if both are set to True. |
4229 4229 | |
4230 4230 | Outputs: |
4231 4231 | A list of list pairs suggesting ranges for input into the excludechan |
4232 4232 | option of renormalization(). |
4233 4233 | """ |
4234 + | |
4235 + | |
4234 4236 | def subsets(chans): |
4235 4237 | """ |
4236 4238 | Purpose: Find subset ranges within an array of consecutive values and |
4237 4239 | return the sub-ranges. |
4238 4240 | """ |
4239 - | from more_itertools import consecutive_groups |
4241 + | class groupby: |
4242 + | # A subset task of the itertools package. |
4243 + | # https://docs.python.org/3/library/itertools.html#itertools.groupby |
4244 + | |
4245 + | # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B |
4246 + | # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D |
4247 + | def __init__(self, iterable, key=None): |
4248 + | if key is None: |
4249 + | key = lambda x: x |
4250 + | self.keyfunc = key |
4251 + | self.it = iter(iterable) |
4252 + | self.tgtkey = self.currkey = self.currvalue = object() |
4253 + | |
4254 + | def __iter__(self): |
4255 + | return self |
4256 + | |
4257 + | def __next__(self): |
4258 + | self.id = object() |
4259 + | while self.currkey == self.tgtkey: |
4260 + | self.currvalue = next(self.it) # Exit on StopIteration |
4261 + | self.currkey = self.keyfunc(self.currvalue) |
4262 + | self.tgtkey = self.currkey |
4263 + | return (self.currkey, self._grouper(self.tgtkey, self.id)) |
4264 + | |
4265 + | def _grouper(self, tgtkey, id): |
4266 + | while self.id is id and self.currkey == tgtkey: |
4267 + | yield self.currvalue |
4268 + | try: |
4269 + | self.currvalue = next(self.it) |
4270 + | except StopIteration: |
4271 + | return |
4272 + | self.currkey = self.keyfunc(self.currvalue) |
4273 + | |
4274 + | def itemgetter(*items): |
4275 + | # A subset task of the operator package. |
4276 + | # https://docs.python.org/3/library/operator.html#operator.itemgetter |
4277 + | if len(items) == 1: |
4278 + | item = items[0] |
4279 + | def g(obj): |
4280 + | return obj[item] |
4281 + | else: |
4282 + | def g(obj): |
4283 + | return tuple(obj[item] for item in items) |
4284 + | return g |
4285 + | |
4286 + | def consecutive_groups(iterable, ordering=lambda x: x): |
4287 + | """ |
4288 + | A subset of the more-itertools package. |
4289 + | https://more-itertools.readthedocs.io/en/stable |
4290 + | /_modules/more_itertools/more.html#consecutive_groups |
4291 + | |
4292 + | Yield groups of consecutive items using :func:`itertools.groupby`. |
4293 + | The *ordering* function determines whether two items are adjacent by |
4294 + | returning their position. |
4295 + | |
4296 + | By default, the ordering function is the identity function. This is |
4297 + | suitable for finding runs of numbers: |
4298 + | |
4299 + | >>> iterable = [1, 10, 11, 12, 20, 30, 31, 32, 33, 40] |
4300 + | >>> for group in consecutive_groups(iterable): |
4301 + | ... print(list(group)) |
4302 + | [1] |
4303 + | [10, 11, 12] |
4304 + | [20] |
4305 + | [30, 31, 32, 33] |
4306 + | [40] |
4307 + | |
4308 + | For finding runs of adjacent letters, try using the :meth:`index` method |
4309 + | of a string of letters: |
4310 + | |
4311 + | >>> from string import ascii_lowercase |
4312 + | >>> iterable = 'abcdfgilmnop' |
4313 + | >>> ordering = ascii_lowercase.index |
4314 + | >>> for group in consecutive_groups(iterable, ordering): |
4315 + | ... print(list(group)) |
4316 + | ['a', 'b', 'c', 'd'] |
4317 + | ['f', 'g'] |
4318 + | ['i'] |
4319 + | ['l', 'm', 'n', 'o', 'p'] |
4320 + | |
4321 + | Each group of consecutive items is an iterator that shares it source with |
4322 + | *iterable*. When an an output group is advanced, the previous group is |
4323 + | no longer available unless its elements are copied (e.g., into a ``list``). |
4324 + | |
4325 + | >>> iterable = [1, 2, 11, 12, 21, 22] |
4326 + | >>> saved_groups = [] |
4327 + | >>> for group in consecutive_groups(iterable): |
4328 + | ... saved_groups.append(list(group)) # Copy group elements |
4329 + | >>> saved_groups |
4330 + | [[1, 2], [11, 12], [21, 22]] |
4331 + | |
4332 + | Borrowed for PL use from https://pypi.org/project/more-itertools/ |
4333 + | """ |
4334 + | for k, g in groupby( |
4335 + | enumerate(iterable), key=lambda x: x[0] - ordering(x[1]) |
4336 + | ): |
4337 + | yield map(itemgetter(1), g) |
4338 + | |
4240 4339 | subsets = [list(group) for group in consecutive_groups(chans)] |
4241 4340 | ranges = [] |
4242 4341 | for ss in subsets: |
4243 4342 | ranges.append([min(ss), max(ss)]) |
4244 4343 | return ranges |
4245 4344 | |
4246 4345 | # Get list of scans that were evaluated |
4247 4346 | scans = list(self.atmMask[target][spw].keys()) |
4248 4347 | |
4249 4348 | # We need to compile a "complete" atmospheric mask. Since the objects may set throughout |