Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala for-loop. Getting index in consice way

Tags:

yield

loops

scala

In this code I want to increment index to put it to each yielding result.

var index=0

for(str <- splitToStrings(text) ) yield  {

  if (index != 0) index += 1               // but index is equal to `0` all the time

  new Word(str, UNKNOWN_FORM, index )
}

Why I can not change index ? And what the best way to implement this logic then, trying to be concise?

like image 588
ses Avatar asked Jun 02 '13 14:06

ses


People also ask

What does index mean in a for loop?

The index value represents the number of the currently executing iteration. More specifically, the body of the loop (the instructions that are executed during each loop repetition) can be said to be iterated as the loop executes.

How do I use zipWithIndex?

The zipWithIndex function is applicable to both Scala's Mutable and Immutable collection data structures. The zipWithIndex method will create a new collection of pairs or Tuple2 elements consisting of the element and its corresponding index. The zipWithIndex method is a member of IterableLike trait.

Which keyword is used to return value from for loop in Scala?

In Scala, the loop's return value is stored in a variable or may return through a function. To do this, you should prefix the body of the 'for' expression with the keyword yield.


4 Answers

The zipWithIndex method on most sequence-like collections will give you a zero-based index, incrementing with each element:

for ((str, index) <- splitToStrings(text).zipWithIndex)
  yield new Word(str, UNKNOWN_FORM, index)
like image 84
Ben James Avatar answered Oct 15 '22 06:10

Ben James


Because initially index is set to 0, thus your condition index != 0 is never executes to true and index is never got incremented. Maybe you don't need this condition? Maybe you can count results afterwards? Now I see that index is used within loop. Then you have to either use @BenJames answer or go recursive.

like image 42
om-nom-nom Avatar answered Oct 15 '22 05:10

om-nom-nom


zipWithIndex will copy and create a new collection, so better make it lazy when the collection is potentially large

for ((str, index) <- splitToStrings(text).view.zipWithIndex)
  yield new Word(str, UNKNOWN_FORM, index)

In fact, if you are working with an indexed sequence, then a more efficient way is to use indices, which produces the range of all indices of this sequence.

val strs = splitToStrings(text)

for(i <- strs.indices) yield  {
  new Word(strs(i), UNKNOWN_FORM, i )
}
like image 3
Max Avatar answered Oct 15 '22 06:10

Max


splitToStrings(text).foldLeft(0,List[Word]){(a,b) => {
   if(a._1!=0) (a._1+1,new Word(str, UNKNOWN_FORM, index) :: b)
   else (a._1,new Word(str, UNKNOWN_FORM, index) :: b)
}}

I am using foldLeft here with a tuple as: starting base with index = 0 and an empty List. I then iterate over each element.

Above a is this tuple. I check the index value and increment it. Else I dont add the index. And I add the new Word to the list.

Ultimately in the end you get a tuple containing the index value and the total List containing all Words.

like image 1
Jatin Avatar answered Oct 15 '22 06:10

Jatin