All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.j5ik2o.intervals.IntervalSeq.scala Maven / Gradle / Ivy

There is a newer version: 1.0.59
Show newest version
package com.github.j5ik2o.intervals

import scala.collection._

/** 区間列(複数の [[Interval]] の列)を表すクラス。
  *
  * @tparam T
  *   [[Interval]] の型
  * @param values
  *   [[Interval]] の列
  * @param ordering
  *   [[Ordering]]
  */
class IntervalSeq[T](val values: Vector[Interval[T]], val ordering: Ordering[Interval[T]]) {

  def append(value: Interval[T]): IntervalSeq[T] = new IntervalSeq(values :+ value)

  def :+(value: Interval[T]): IntervalSeq[T] = append(value)

  def isEmpty: Boolean = values.isEmpty

  def nonEmpty: Boolean = !isEmpty

  /** インスタンスを生成する。
    *
    * `intervals`は空を利用し、`ordering`は`UpperLowerOrdering[T](true, false)`を利用する。
    */
  def this() =
    this(Vector.empty, UpperLowerOrdering[T](inverseLower = true, inverseUpper = false))

  /** インスタンスを生成する。
    *
    * `ordering`は`UpperLowerOrdering[T](true, false)`を利用する。
    *
    * @param values
    *   [[Interval]] の列
    */
  def this(values: Vector[Interval[T]]) =
    this(values, UpperLowerOrdering[T](inverseLower = true, inverseUpper = false))

  /** 全ての要素区間を内包する、最小の区間を返す。
    *
    * @return
    *   全ての要素区間を内包する、最小の区間
    * @throws IllegalStateException
    *   要素が1つもない場合
    */
  lazy val extent: Option[Interval[T]] = {
    values.toList match {
      case Nil     => None
      case List(e) => Some(e)
      case firstInterval :: _ =>
        val lower = values.map(_.lowerLimitObject).min
        val upper = values.map(_.upperLimitObject).max
        Some(firstInterval.newOfSameType(lower.value, lower.closed, upper.value, upper.closed))
    }
  }

  /** ソート済みの区間で、隣り合った区間同士に挟まれる区間を区間列として返す。
    *
    * 結果の区間列の `java.util.Comparator` は、この区間列の `java.util.Comparator` を流用する。
    *
    * 区間数が2つ未満の場合は、空の区間列を返す。また、区間同士が重なっていたり接していた場合は、 その区間は結果の要素に含まない。全てが重なっている場合は、空の区間列を返す。
    *
    * @return
    *   ギャップ区間列
    */
  lazy val gaps: IntervalSeq[T] = {
    if (values.size < 2) {
      new IntervalSeq()
    } else {
      val values = (1 until this.values.size).flatMap { i =>
        val left  = this.values(i - 1)
        val right = this.values(i)
        val gap   = left.gap(right)
        if (gap.isEmpty) {
          None
        } else {
          Some(gap)
        }
      }
      IntervalSeq(values.toVector)
    }
  }

  /** ソート済みの区間で、隣り合った区間同士が重なっている区間を区間列として返す。
    *
    * 結果の区間列の [[java.util.Comparator]] は、この区間列の [[java.util.Comparator]] を流用する。
    *
    * 区間数が2つ未満の場合は、空の区間列を返す。また、区間同士が重ならなかったり接していた場合は、 その区間は結果の要素に含まない。全てが重ならない場合は、空の区間列を返す。
    *
    * @return
    *   共通区間列
    */
  lazy val intersections: IntervalSeq[T] = {
    if (values.size < 2) {
      new IntervalSeq()
    } else {
      val values = (1 until this.values.size).flatMap { i =>
        val left  = this.values(i - 1)
        val right = this.values(i)
        val gap   = left.intersect(right)
        if (gap.isEmpty) None
        else Some(gap)
      }
      IntervalSeq(values.toVector)
    }
  }

  def iterator: Iterator[Interval[T]] = values.sorted(ordering).iterator

  def length: Int = values.length

  def apply(idx: Int): Interval[T] = values(idx)

  def toSeq: Seq[Interval[T]] = values

}

/** `IntervalSeq`コンパニオンオブジェクト
  */
object IntervalSeq {

  /** インスタンスを生成する。
    *
    * @tparam T
    *   限界値の型
    * @param intervals
    *   [[Interval]] の列
    * @return
    *   [[IntervalSeq]]
    */
  def apply[T](intervals: Vector[Interval[T]]): IntervalSeq[T] =
    new IntervalSeq(intervals)

  /** インスタンスを生成する。
    *
    * @tparam T
    *   限界値の型
    * @return
    *   [[IntervalSeq]]
    */
  def apply[T](): IntervalSeq[T] = new IntervalSeq[T]()

  /** 抽出子メソッド。
    *
    * @tparam T
    *   限界値の型
    * @return
    *   構成要素
    */
  def unapply[T](intervalSeq: IntervalSeq[T]): Option[(Seq[Interval[T]], Ordering[Interval[T]])] =
    Some(intervalSeq.values, intervalSeq.ordering)

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy