Effective way to check if passing value has more than 1 element in Scala

I need to check if Traversable (which I already know as nonEmpty ) has one or more elements.

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

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

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

+5
source share
4 answers

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

I suggest using take :

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

take declared to return the entire collection if the length of the collection is less than the take argument. Thus, there will be no error if the collection is empty or has only one item. On the other hand, if the collection is huge, take will work O (1) times, though. Internally, take will begin to repeat your collection, follow two steps, and break, returning items to the new collection.

UPD: I changed the condition to fit the question exactly

+7
source

Not everything will be the same, but let it take the worst case scenario, where it is List . last will use the entire List only to access this element, just like size .

tail.nonEmpty obtained from matching the head :: tail pattern, which does not require the use of the entire List . If you already know that the list is not empty, this should be an obvious choice.

But not all tail operations take constant time, like a List : Scala Collection performance

+3
source

You can view what you are viewing. You can slice a TraversableView lazily.

The starting star is because REPL prints some result.

 scala> val t: Traversable[Int] = Stream continually { println("*"); 42 } * t: Traversable[Int] = Stream(42, ?) scala> t.view.slice(0,2).size * res1: Int = 2 scala> val t: Traversable[Int] = Stream.fill(1) { println("*"); 42 } * t: Traversable[Int] = Stream(42, ?) scala> t.view.slice(0,2).size res2: Int = 1 

The advantage is that there is no intermediate collection.

 scala> val t: Traversable[_] = Map((1 to 10) map ((_, "x")): _*) t: Traversable[_] = Map(5 -> x, 10 -> x, 1 -> x, 6 -> x, 9 -> x, 2 -> x, 7 -> x, 3 -> x, 8 -> x, 4 -> x) scala> t.take(2) res3: Traversable[Any] = Map(5 -> x, 10 -> x) 

This returns a non-optimized map, for example:

 scala> res3.getClass res4: Class[_ <: Traversable[Any]] = class scala.collection.immutable.HashMap$HashTrieMap scala> Map(1->"x",2->"x").getClass res5: Class[_ <: scala.collection.immutable.Map[Int,String]] = class scala.collection.immutable.Map$Map2 
+1
source

How about matching patterns?

  itrbl match { case _::Nil => "one"; case _=>"more" } 
0
source

Source: https://habr.com/ru/post/1203399/


All Articles