def __collapse_stranded(s, proc_strands, names=False, verbose=False):
def get_first_matching_index(s, proc_strands):<EOL><INDENT>for i in range(<NUM_LIT:0>, len(s)):<EOL><INDENT>if s[i].strand in proc_strands:<EOL><INDENT>return i<EOL><DEDENT><DEDENT>return None<EOL><DEDENT>if proc_strands not in [set("<STR_LIT:+>"), set("<STR_LIT:->"), set(["<STR_LIT:+>", "<STR_LIT:->"])]:<EOL><INDENT>raise GenomicIntervalError("<STR_LIT>" +<EOL>"<STR_LIT:U+002C>".join(proc_strands) + "<STR_LIT>" +<EOL>"<STR_LIT>")<EOL><DEDENT>first_index = get_first_matching_index(s, proc_strands)<EOL>if first_index is None:<EOL><INDENT>return []<EOL><DEDENT>res = []<EOL>current = copy.copy(s[first_index])<EOL>current.strand = '<STR_LIT:+>' if (proc_strands == set("<STR_LIT:+>") or<EOL>proc_strands == set(["<STR_LIT:+>", "<STR_LIT:->"])) else '<STR_LIT:->'<EOL>current.score = <NUM_LIT:0><EOL>current.name = "<STR_LIT:X>" if not names else set(s[first_index].name)<EOL>for i in range(first_index + <NUM_LIT:1>, len(s)):<EOL><INDENT>if s[i].strand not in proc_strands:<EOL><INDENT>continue<EOL><DEDENT>if (s[i].chrom < s[i - <NUM_LIT:1>].chrom) or(s[i].chrom == s[i - <NUM_LIT:1>].chrom and s[i].start < s[i - <NUM_LIT:1>].start):<EOL><INDENT>raise GenomicIntervalError("<STR_LIT>" +<EOL>"<STR_LIT>" + str(s[i - <NUM_LIT:1>]) + "<STR_LIT>" +<EOL>"<STR_LIT>" + str(s[i]))<EOL><DEDENT>if s[i].start > current.end or s[i].chrom != current.chrom:<EOL><INDENT>if names:<EOL><INDENT>current.name = "<STR_LIT:;>".join(current.name)<EOL><DEDENT>res.append(current)<EOL>current = copy.copy(s[i])<EOL>current.strand = '<STR_LIT:+>' if (proc_strands == set("<STR_LIT:+>") or<EOL>proc_strands == set(["<STR_LIT:+>", "<STR_LIT:->"])) else '<STR_LIT:->'<EOL>current.score = <NUM_LIT:0><EOL>current.name = "<STR_LIT:X>" if not names else set(s[i].name)<EOL><DEDENT>else:<EOL><INDENT>current.end = max(s[i].end, current.end)<EOL>if names:<EOL><INDENT>current.name.add(s[i].name)<EOL><DEDENT><DEDENT><DEDENT>if names:<EOL><INDENT>current.name = "<STR_LIT:;>".join(current.name)<EOL><DEDENT>res.append(current)<EOL>return res<EOL>
Get the union of a set of genomic intervals.

given a list of genomic intervals with chromosome, start, end and strand
fields, collapse those intervals with strand in the set <proc_strands>
into a set of non-overlapping intervals. Other intervals are ignored.
Intervals must be sorted by chromosome and then start coordinate.

:note: O(n) time, O(n) space
:return:  list of intervals that define the collapsed regions. Note that
          these are all new objects, no existing object from s is returned
          or altered. Returned regions will all have name "X" and score 0
:param s:            list of genomic regions to collapse
:param proc_strands: set of acceptable strands; ignore input intervals
                     with strand not found in this set.
:param names:        if True, accumulate region names. If false, all output
                     regions have name "X"
:param verbose:      if True, output progress message to stderr.
:raise GenomicIntervalError: if the input regions are not correctly sorted
                             (chromosome then start)