Когда вы переходите с императивного языка на Scala, одна из самых больших трудностей, с которыми вы сталкиваетесь, — «как использовать неизменяемую коллекцию в распространенных сценариях кодирования».

Я столкнулся с той же проблемой, когда перешел с C++ на Scala. Я сопротивлялся этому так же, как и сейчас, я вижу, что люди сопротивляются. Но со временем я понял, что неизменяемые коллекции позволяют сосредоточиться на проблеме, а не на рутинной бухгалтерии. Это делает вашу программу более читабельной. И прежде всего это дает вам чувство удовлетворения, которое трудно получить в других языках.

В этой серии постов я решу некоторые популярные проблемы с неизменяемыми коллекциями.

Отказ от ответственности. Для каждой проблемы, обсуждаемой здесь (и в будущих сообщениях этой серии), я использую решение, которое достаточно простое и которое я предпочтительно буду использовать в рабочем коде. (Не тот причудливый, который вы будете использовать, чтобы произвести впечатление на интервьюера и который работает с нереалистичными входными данными).

Проблема- «Максимальное население в диапазоне лет» или «Максимальные интервалы перекрываются»

Вариант 1По списку людей с указанием года рождения и года смерти каждого человека найдите год с наибольшим населением.

Вариант 2. Рассмотрим большую вечеринку, в которой ведется журнал учета времени входа и выхода гостей. Найдите время, когда на вечеринке будет максимальное количество гостей. Обратите внимание, что записи в реестре не в любом порядке

Решение -

По сути, нам нужно перебирать каждого человека, и для каждого года, который он прожил, нам нужно увеличивать количество на карте. А потом выбрать максимум.

Допустим, ниже приведены структура данных и ввод, с которыми мы будем иметь дело.

case class years(birth: Int, death: Int)
val input: Seq[years] = Seq(years(1962, 2015), years(1967, 2005), years(1912, 1975) , years(1902, 1999), years(1942, 2000))

Скала-код может выглядеть так

import scala.collection.mutable.Map  
 
val yearMap = Map.empty[Int, Int].withDefaultValue(0)
input foreach { person =>
  for {
     alive <- person.birth to person.death
   } yearMap(alive) += 1
   yearMap(person.death) -= 1
 }
 val max = yearMap.maxBy {case (key, value) => value}
   println(max)
 }
}

Но этот код использует изменяемую карту. Можем и без него. Мы будем использовать flatMap, groupBy и mapValues. а также until .

С этим .. выше код меняется на этот

val max = (input flatMap { y => y.birth until y.death } groupBy identity).mapValues(_.size).maxBy(_._2)
println(max)

Код прост, если вы читаете его, не ища шаблон, который у вас есть в первом решении.

 y => y.birth until y.death 

дает вам список всех лет жизни человека. (не пропустите untilздесь, что исключает год смерти.

input flatMap { y => y.birth until y.death }

Получает этот список для всех на входе. Здесь мы используем flatMap, который преобразует List[List[Int] в List[Int]. Это более умная версия использования .map().flatten .

input flatMap { y => y.birth until y.death } groupBy identity

над строкой сгруппируйте их по значению. Что-то вроде следующего

1970 -> Seq(1970,1970) // 1970 appears two times
1923 -> Seq(1923) // appars once

и наконец

(input flatMap { y => y.birth until y.death } groupBy identity).mapValues(_.size)

измените приведенный выше пример на

1970 -> 2// 1970 appears two times
1923 -> 1// appars once

Вот и все. Остальной код должен найти максимум. Теперь еще раз просмотрите полное решение.

(input flatMap { y => y.birth until y.death } groupBy identity).mapValues(_.size).maxBy(_._2)

Всего одна строка для решения проблемы.

Надеюсь, это поможет вам в обучении. Пожалуйста, поделитесь своим мнением.

Спасибо