# How to avoid implemented the same function twice

I needed to call this function `takeNsmallest` on a `List` and also on a `MapView`. So I duplicated the function and only changed the type declarations.
Is there a better way in this case? Should I write the function once and just use cleverer declarations?

``````  def takeNsmallest[T](n: Int, data: List[T], measure: T => Double): List[T] = {
if (n == 0 || data.isEmpty)
List()
else {
data
.foldLeft(MaxSizeList[T](n, measure, List[T]())) { (acc, next) => MaxSizeList(n, measure, next :: acc.items) }
.items
}.sortBy(measure)
}

def takeNsmallest[A,B](n: Int, data: MapView[A,B], measure: ((A,B)) => Double): List[(A,B)] = {
if (n == 0 || data.isEmpty)
List()
else {
data
.foldLeft(MaxSizeList[(A,B)](n, measure, List[(A,B)]())) { (acc, next) => MaxSizeList(n, measure, next :: acc.items) }
.items
}.sortBy(measure)
}
``````

I think this should work:

``````def takeNsmallest[T](n: Int, data: IterableOnce[T], measure: T => Double): List[T] =
if (n == 0)
List.empty[T]
else
data
.iterator
.foldLeft(MaxSizeList[T](n, measure, List.empty[T])) {
(acc, next) => MaxSizeList(n, measure, next :: acc.items)
}.items
.sortBy(measure)
``````

ahhh, so the same code doesn’t work. we have to add the `.iterator` call? Interesting.

Yeah, that is because `IterableOnce` doesn’t provide any methods at all.
Rather, it just provides a way to get an `Iterator`

I think you could use `Iterable` instead of `IterableOnce`.

Why?
That would just allow fewer data types without any advantage to the code.

No reason other than that the code would work without `.iterator`.

That’s an interesting question, whether a “native” `foldLeft` is more desirable.

`List` has both `foldLeft` and `iterator` that use `tail`, so maybe the differential cost is only an indirection. `Map`s resort to `IterableOnceOps`.

Arrays and `LazyList` get dedicated `foldLeft` as well.

Doc says minimal `IterableOnce` is to support parallel collections, which would not want to inherit `IterableOnceOps`.

The method could take `IterableOnceOps`, but probably no one does that.