Knows Not Much Knows Not Much - 26 days ago 7
Scala Question

Counter inside of scala for comprehension

I have this piece of code.

for {
country <- getCountryList
city <- getCityListForCountry(country)
person <- getPersonListForCity(person)
} {...}


When we run this code, we need to have a counter inside the body of the loop which increments every time the loop executes. This counter needs to show the number of people processed per country. So it has to reset itself to 0 every time we start executing the loop for a new country.

I tried

for {
country <- getCountryList
counterPerCountry = 0
city <- getCityListForCountry(country)
person <- getPersonListForCity(city)
} {counterPerCountry = counterPerCountry + 1; ...}


but this says that I am trying to reassign a value to val.

so I tried

var counterPerCountry = 0
for {
country <- getCountryList
counterPerCountry = 0
city <- getCityListForCountry(country)
person <- getPersonListForCity(city)
} {counterPerCountry = counterPerCountry + 1; ...}


also tried

for {
country <- getCountryList
var counterPerCountry = 0
city <- getCityListForCountry(country)
person <- getPersonListForCity(city)
} {counterPerCountry = counterPerCountry + 1; ...}

Answer

I agree with @pamu that a for-comprehension does not seem the like a natural choice here. But if you turn the for comprehension into the underlying operations, I think you can get a solution that, while not as readable as a for comprehension, works with Scala's functional style and avoids mutable variables. I'm thinking of something along this line:

getCountryList flatMap (country => 
  (getCityListForCountry(country) flatMap (city => 
     getPersonListForCity(city))
  ).zipWithIndex
)

That should yield a list of (person, index) tuples where the index starts at zero for each country.

The inner part could be turned back into a for comprehension, but I'm not sure whether that would improve readability.