Skip to content

Instantly share code, notes, and snippets.

@joshlemer
Last active December 10, 2018 00:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshlemer/e403df6846568f687df2d73af809bebd to your computer and use it in GitHub Desktop.
Save joshlemer/e403df6846568f687df2d73af809bebd to your computer and use it in GitHub Desktop.
Nel
import scala.collection.mutable
import scala.collection.immutable.{AbstractSeq, LinearSeq, LinearSeqOps, StrictOptimizedSeqOps}
final class Nel[+A](override val head: A, override val tail: List[A])
extends AbstractSeq[A]
with LinearSeq[A]
with LinearSeqOps[A, LinearSeq, LinearSeq[A]]
with StrictOptimizedSeqOps[A, LinearSeq, LinearSeq[A]] {
override def toList: List[A] = head :: tail
private[this] def fromList[A0 >: A](list: List[A0]): Nel[A0] = new Nel(list.head, list.tail)
override def distinctBy[B](f: A => B): Nel[A] = fromList(toList.distinctBy(f))
override def updated[B >: A](index: Int, elem: B): Nel[B] =
if (index == 0) new Nel(elem, tail)
else new Nel(head, tail.updated(index - 1, elem))
override def prepended[B >: A](elem: B): Nel[B] = new Nel(elem, head :: tail)
override def appended[B >: A](elem: B): Nel[B] = new Nel(head, tail.appended(elem))
override def appendedAll[B >: A](suffix: IterableOnce[B]): Nel[B] = new Nel(head, tail.appendedAll(suffix))
override def prependedAll[B >: A](prefix: IterableOnce[B]): Nel[B] = fromList(toList.prependedAll(prefix))
override def padTo[B >: A](len: Int, elem: B): Nel[B] = fromList(toList.padTo(len, elem))
override def unzip[A1, A2](implicit asPair: A => (A1, A2)): (Nel[A1], Nel[A2]) = {
val (h1, h2) = asPair(head)
val (t1, t2) = tail.unzip
(new Nel(h1, t1), new Nel(h2, t2))
}
override def unzip3[A1, A2, A3](implicit asTriple: A => (A1, A2, A3)): (Nel[A1], Nel[A2], Nel[A3]) = {
val (h1, h2, h3) = asTriple(head)
val (t1, t2, t3) = tail.unzip3
(new Nel(h1, t1), new Nel(h2, t2), new Nel(h3, t3))
}
override def map[B](f: A => B): Nel[B] = new Nel(f(head), tail.map(f))
override def concat[B >: A](suffix: IterableOnce[B]): Nel[B] = new Nel(head, tail.concat(suffix))
override def sorted[B >: A](implicit ord: Ordering[B]): Nel[A] = fromList(toList.sorted(ord))
override def sortWith(lt: (A, A) => Boolean): Nel[A] = fromList(toList.sortWith(lt))
override def sortBy[B](f: A => B)(implicit ord: Ordering[B]): Nel[A] = fromList(toList.sortBy(f))
override def isEmpty: Boolean = false
override def className: String = "Nel"
override def iterator: Iterator[A] = toList.iterator
}
// Companion doesn't conform to any existing Factory trait.
// That's not the end of the world -- neither does MapView, IndexedSeqView, SeqView, IntMap, or AnyRefMap
object Nel {
def from[A](source: IterableOnce[A]): Option[Nel[A]] = source match {
case nel: Nel[A] => Some(nel)
case h :: t => Some(new Nel(h, t))
case other =>
val iter = other.iterator
if (iter.hasNext) {
val head = iter.next()
Some(new Nel(head, List.from(iter)))
} else None
}
def newBuilder[A]: mutable.Builder[A, Option[Nel[A]]] = List.newBuilder[A].mapResult {
case h :: t => Some(new Nel(h, t))
case _ => None
}
// if you provide an initial element, we can create a builder for Nels
def newBuilder[A](head: A): mutable.Builder[A, Nel[A]] = List.newBuilder[A].mapResult(new Nel(head, _))
def apply[A](head: A, tail: A*): Nel[A] = new Nel(head, tail.toList)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment