## 24. `yearBrackets()`: Display a bracketed list of years worked

When displaying the list of years when a particular circle was counted, the general case is actually fairly complex, because years can be skipped, and (especially in the early decades) many circles were counted more than once in a year. Here are some examples.

 `[38]` Counted once in year 38. `[72–84]` Counted every year from the 72nd through the 84th. `[72–79,81–84]` Counted from the 72nd through the 84th but missed the 80th. `[1,7(5),8(4),9(3),11,35, 37–72]` Typical circle (Belmont, MA) in the early years: lots of multiply-counted years. `[4-6,7(2)]` The raw list of years for this case is ```[4, 5, 6, 7, 7]```. Note that the range starting with 4 ends at 6, not 7, because the 7 is repeated.

Our `effortList` argument is a list of `Effort` instances as input. Our task is to form these into hyphenated groups, but avoid combining ranges with multiply-counted years. Here is the algorithm.

1. We set `numberList` to a list of the year numbers in the `effortList`. We also set up a `resultList` which will hold the character form of each resulting group.

2. From this, we first form `pairList`, a list of pairs ```(year_no, count)```, sorted by year number.

3. We find which set of one or more initial rows of `pairList` form a group. We then remove those rows and add the equivalent character representation to `resultList`. This step is repeated until `pairList` is exhausted.

4. The result is the concatenated elements of `resultList`, separated by commas and enclosed in brackets.

cbchistlib.py
```# - - -   y e a r B r a c k e t s

def yearBrackets(effortList):
'''Convert a list of years to a bracketed list of groups.

[ effortList is a list of Effort instances ->
return a string of the form "[G0,G1,...]" such that
each group Gi is a single year ("YYY"), bracketed range of
years ("YYY-YYY"), or multiply-counted group ("YYY (N)") ]
'''
#-- 1
# [ resultList  :=  a new, empty list
#   numberList  :=  list of the year numbers in effortList as ints ]
resultList = []
numberList = [ int(effort.year_no)
for effort in effortList ]

```

For the logical that forms the list of `(year_no, count)` tuples, see Section 25, “`countValues()`: Summarize a list of years”.

cbchistlib.py
```    #-- 2
# [ pairList  :=  a list of pairs (value, count) representing
#       numberList ]
pairList = countValues(numberList)
```

Each call to Section 26, “`peelGroup()`: Find the first date group in a list” removes one or more rows from the front of `pairList` and returns the equivalent character form.

cbchistlib.py
```    #-- 3
# [ pairList  :=  empty
#   resultList  +:=  strings representing the sequences,
#       repeated value groups, and single values in pairList ]
while len(pairList) > 0:
#-- 3 body
# [ pairList  :=  pairList with the initial sequence,
#       repeated value group, or single value removed
#   resultList  :=  string representing the removed group ]
resultList.append ( peelGroup ( pairList ) )

#-- 4
# [ return the concatenated, comma-separated elements of resultList
#       wrapped in a pair of square brackets ]
return ("[%s]" % ','.join(resultList))
```