Когда вы переходите с императивного языка на 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)
Всего одна строка для решения проблемы.
Надеюсь, это поможет вам в обучении. Пожалуйста, поделитесь своим мнением.
Спасибо