Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficient way to check if a traversable has more than 1 element in Scala

I need to check if a Traversable (which I already know to be nonEmpty) has a single element or more.

I could use size, but (tell me if I'm wrong) I suspect that this could be O(n), and traverse the collection to compute it.

I could check if tail.nonEmpty, or if .head != .last

Which are the pros and cons of the two approaches? Is there a better way? (for example, will .last do a full iteration as well?)

like image 920
Lorenzo Dematté Avatar asked Sep 25 '14 13:09

Lorenzo Dematté


People also ask

What does ++ mean in Scala?

The effect of = can also be used to easily understand what ++= would do. Since ++ generally represents concatenation of two collections, ++= would mean an "in place" update of a collection with another collection by concatenating the second collection to the first.

What is traversable in Scala?

Introduction: A root trait of the entire class of the Scala collections is Trait Traversable. It is available at the uppermost position of the collection hierarchy. It has uniquely one abstract operation, which is foreach. Here each of the operations are assured to be executed in a single-threaded approach.

Does Scala set preserve order?

In scala, ListSet class implements immutable sets using a list-based data structure. Elements are stored in reversed insertion order, That means the newest element is at the head of the list. It maintains insertion order.

What is iterable in Scala?

Iterable: A base trait for iterable collections. This is a base trait for all Scala collections that define an iterator method to step through one-by-one the collection's elements.


2 Answers

All approaches that cut elements from beginning of the collection and return tail are inefficient. For example tail for List is O(1), while tail for Array is O(N). Same with drop.

I propose using take:

 list.take(2).size == 1 // list is singleton

take is declared to return whole collection if collection length is less that take's argument. Thus there will be no error if collection is empty or has only one element. On the other hand if collection is huge take will run in O(1) time nevertheless. Internally take will start iterating your collection, take two steps and break, putting elements in new collection to return.

UPD: I changed condition to exactly match the question

like image 128
Aivean Avatar answered Sep 17 '22 18:09

Aivean


Not all will be the same, but let's take a worst case scenario where it's a List. last will consume the entire List just to access that element, as will size.

tail.nonEmpty is obtained from a head :: tail pattern match, which doesn't need to consume the entire List. If you already know the list to be non-empty, this should be the obvious choice.

But not all tail operations take constant time like a List: Scala Collections Performance

like image 24
Michael Zajac Avatar answered Sep 17 '22 18:09

Michael Zajac