Iterate over multiple BED format files simultaneously and yield lists of
  genomic intervals for each matching set of intervals found. By default,
  regions which are not found in all files will be skipped (mirror = false).
  Optionally (by setting mirror to true) if a file is missing an interval,
  it can be added on-the-fly, and will have the same chrom, start and end and
  name as in other files. The score will be taken from the first file in
  inputStreams if mirrorScore is not set, otherwise that value will be used.

  :param inputStreams: a list of input streams in BED format
  :param mirror: if true, add missing elements so all streams contain the
                 same elements. Inserted elements will have the same
  :param ignoreStrand: ignore strand when comparing elements for equality?
  :param ignoreScore: ignore score when comparing elements for equality?
  :param ignoreScore: ignore name when comparing elements for equality?
  :param sortedby: must be set to one of the sorting orders for BED streams;
                   we require the streams to be sorted in some fashion.
  :param scoreType: interpret scores as what type? Defaults to float, which
                    is generally the most flexible.

def pairedBEDIterator(inputStreams, mirror=False, mirrorScore=None,
                      ignoreStrand=False, ignoreScore=True, ignoreName=True,
                      sortedby=ITERATOR_SORTED_END, scoreType=float,
                      verbose=False):
  """
  Iterate over multiple BED format files simultaneously and yield lists of
  genomic intervals for each matching set of intervals found. By default,
  regions which are not found in all files will be skipped (mirror = false).
  Optionally (by setting mirror to true) if a file is missing an interval,
  it can be added on-the-fly, and will have the same chrom, start and end and
  name as in other files. The score will be taken from the first file in
  inputStreams if mirrorScore is not set, otherwise that value will be used.

  :param inputStreams: a list of input streams in BED format
  :param mirror: if true, add missing elements so all streams contain the
                 same elements. Inserted elements will have the same
  :param ignoreStrand: ignore strand when comparing elements for equality?
  :param ignoreScore: ignore score when comparing elements for equality?
  :param ignoreScore: ignore name when comparing elements for equality?
  :param sortedby: must be set to one of the sorting orders for BED streams;
                   we require the streams to be sorted in some fashion.
  :param scoreType: interpret scores as what type? Defaults to float, which
                    is generally the most flexible.
  """

  # let's build our sorting order...
  sortOrder = ["chrom"]
  if sortedby == ITERATOR_SORTED_START:
    sortOrder.append("start")
    sortOrder.append("end")
  elif sortedby == ITERATOR_SORTED_END:
    sortOrder.append("end")
    sortOrder.append("start")
  if not ignoreStrand:
    sortOrder.append("strand")
  if not ignoreName:
    sortOrder.append("name")
  if not ignoreScore:
    sortOrder.append("score")
  keyFunc = attrgetter(*sortOrder)

  def next_item(iterator):
    """ little internal function to return the next item, or None """
    try:
      return iterator.next()
    except StopIteration:
      return None

  bIterators = [BEDIterator(bfh, verbose=verbose,
                            sortedby=sortedby,
                            scoreType=scoreType) for bfh in inputStreams]
  elements = [next_item(it) for it in bIterators]

  while True:
    assert(len(elements) >= 2)
    if None not in elements and len(set([keyFunc(x) for x in elements])) == 1:
      # All equal -- yield and move on for all streams
      yield [e for e in elements]
      elements = [next_item(it) for it in bIterators]
    else:
      # something wasn't equal.. find the smallest thing, it's about to drop
      # out of range and will never have the chance to match anything again
      minElement = min([x for x in elements if x is not None], key=keyFunc)
      minIndices = [i for i in range(0, len(elements))
                    if elements[i] is not None and
                    keyFunc(elements[i]) == keyFunc(minElement)]
      if mirror:
        # mirror the min item for any streams in which it doesn't match
        score = minElement.score if mirrorScore is None else mirrorScore
        yield [elements[i] if i in minIndices
               else GenomicInterval(minElement.chrom, minElement.start,
                                    minElement.end, minElement.name,
                                    score, minElement.strand,
                                    scoreType=scoreType)
               for i in range(0, len(elements))]

      # move the smallest element onwards now, we're done with it
      for index in minIndices:
        elements[index] = next_item(bIterators[index])

    # stop once all streams are exhausted
    if reduce(lambda x, y: x and y, [e is None for e in elements]):
      break