docs: def get_distinct_segments(self, left_offset = 0, right_offset = 0, sequence_length = None):
          '''Returns a list of segments (pairs of start and end positions) based on the loop definitions. The returned segments
              merge overlapping loops e.g. if the loops file contains sections 32-40, 23-30, 28-33, and 43-46 then the returned
              segments will be [(23, 40), (43, 46)].
              This may not be the fastest way to calculate this (numpy?) but that is probably not an issue.
  
              The offsets are used to select the residues surrounding the loop regions. For example, i.e. if a sequence segment
              is 7 residues long at positions 13-19 and we require 9-mers, we must consider the segment from positions 5-27 so
              that all possible 9-mers are considered.
          '''
  
          # Create a unique, sorted list of all loop terminus positions
          positions = set()
          for l in self.data:
              assert(l['start'] <= l['end'])
              if sequence_length:
                  # If we know the sequence length then we can return valid positions
                  positions = positions.union(range(max(1, l['start'] - left_offset + 1), min(sequence_length + 1, l['end'] + 1 + right_offset - 1))) # For clarity, I did not simplify the expressions. The left_offset requires a +1 to be added, the right_offset requires a -1 to be added. The right offset also requires a +1 due to the way Python splicing works.
              else:
                  # Otherwise, we may return positions outside the sequence length however Python splicing can handle this gracefully
                  positions = positions.union(range(max(1, l['start'] - left_offset + 1), l['end'] + 1 + right_offset - 1)) # For clarity, I did not simplify the expressions. The left_offset requires a +1 to be added, the right_offset requires a -1 to be added. The right offset also requires a +1 due to the way Python splicing works.
          positions = sorted(positions)
  
          # Iterate through the list to define the segments
          segments = []
          current_start = None
          last_position = None
          for p in positions:
              if current_start == None:
                  current_start = p
                  last_position = p
              else:
                  if p == last_position + 1:
                      last_position = p
                  else:
                      segments.append((current_start, last_position))
                      current_start = p
                      last_position = p
          if current_start and last_position:
              segments.append((current_start, last_position))
          return segments