@@ -604,6 +604,14 @@ def unique_value_groups(
604
604
605
605
606
606
def season_to_month_tuple (seasons : Sequence [str ]) -> tuple [tuple [int , ...], ...]:
607
+ """
608
+ >>> season_to_month_tuple(["DJF", "MAM", "JJA", "SON"])
609
+ ((12, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11))
610
+ >>> season_to_month_tuple(["DJFM", "MAMJ", "JJAS", "SOND"])
611
+ ((12, 1, 2, 3), (3, 4, 5, 6), (6, 7, 8, 9), (9, 10, 11, 12))
612
+ >>> season_to_month_tuple(["DJFM", "SOND"])
613
+ ((12, 1, 2, 3), (9, 10, 11, 12))
614
+ """
607
615
initials = "JFMAMJJASOND"
608
616
starts = dict (
609
617
("" .join (s ), i + 1 )
@@ -629,7 +637,7 @@ def season_to_month_tuple(seasons: Sequence[str]) -> tuple[tuple[int, ...], ...]
629
637
return tuple (result )
630
638
631
639
632
- def inds_to_string (asints : tuple [tuple [int , ...], ...]) -> tuple [str , ...]:
640
+ def inds_to_season_string (asints : tuple [tuple [int , ...], ...]) -> tuple [str , ...]:
633
641
inits = "JFMAMJJASOND"
634
642
return tuple ("" .join ([inits [i_ - 1 ] for i_ in t ]) for t in asints )
635
643
@@ -660,24 +668,36 @@ def is_sorted_periodic(lst):
660
668
return lst [- 1 ] <= lst [0 ]
661
669
662
670
663
- @dataclass
671
+ @dataclass ( kw_only = True , frozen = True )
664
672
class SeasonsGroup :
665
673
seasons : tuple [str , ...]
674
+ # tuple[integer months] corresponding to each season
666
675
inds : tuple [tuple [int , ...], ...]
676
+ # integer code for each season, this is not simply range(len(seasons))
677
+ # when the seasons have overlaps
667
678
codes : Sequence [int ]
668
679
669
680
670
681
def find_independent_seasons (seasons : Sequence [str ]) -> Sequence [SeasonsGroup ]:
671
682
"""
672
683
Iterates though a list of seasons e.g. ["DJF", "FMA", ...],
673
684
and splits that into multiple sequences of non-overlapping seasons.
685
+
686
+ >>> find_independent_seasons(
687
+ ... ["DJF", "FMA", "AMJ", "JJA", "ASO", "OND"]
688
+ ... ) # doctest: +NORMALIZE_WHITESPACE
689
+ [SeasonsGroup(seasons=('DJF', 'AMJ', 'ASO'), inds=((12, 1, 2), (4, 5, 6), (8, 9, 10)), codes=[0, 2, 4]),
690
+ SeasonsGroup(seasons=('FMA', 'JJA', 'OND'), inds=((2, 3, 4), (6, 7, 8), (10, 11, 12)), codes=[1, 3, 5])]
691
+
692
+ >>> find_independent_seasons(["DJF", "MAM", "JJA", "SON"])
693
+ [SeasonsGroup(seasons=('DJF', 'MAM', 'JJA', 'SON'), inds=((12, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11)), codes=[0, 1, 2, 3])]
674
694
"""
675
695
season_inds = season_to_month_tuple (seasons )
676
696
grouped = defaultdict (list )
677
697
codes = defaultdict (list )
678
698
seen : set [tuple [int , ...]] = set ()
679
699
idx = 0
680
- # This is quadratic, but the length of seasons is at most 12
700
+ # This is quadratic, but the number of seasons is at most 12
681
701
for i , current in enumerate (season_inds ):
682
702
# Start with a group
683
703
if current not in seen :
@@ -699,7 +719,7 @@ def find_independent_seasons(seasons: Sequence[str]) -> Sequence[SeasonsGroup]:
699
719
700
720
grouped_ints = tuple (tuple (idx ) for idx in grouped .values () if idx )
701
721
return [
702
- SeasonsGroup (seasons = inds_to_string (inds ), inds = inds , codes = codes )
722
+ SeasonsGroup (seasons = inds_to_season_string (inds ), inds = inds , codes = codes )
703
723
for inds , codes in zip (grouped_ints , codes .values (), strict = False )
704
724
]
705
725
0 commit comments