Ayrat
ща попробую на for написать
Vasily
Будет покрасивше
Dr. Friedrich
Будет покрасивше
А мне кажется, что нет. Но это вкусовщина.
Ayrat
@vshapenko императивненько def stockSummary2(lstOfArt: Array[String], lstOfCat: Array[String]): String = { val catWithQtyMap: Map[String, Int] = Map().withDefaultValue(0) lstOfArt foreach(art => { val artMatch = artRegex.findFirstMatchIn(art) if (artMatch.isEmpty) throw new Exception(s"wrong art - $art") val category = artMatch.get.group(1) val qty = artMatch.get.group(2).toInt val oldQty = catWithQtyMap(category) catWithQtyMap += (category -> (oldQty + qty)) }) lstOfCat.toStream .map(cat => s"($cat : ${catWithQtyMap(cat)})") .mkString(" - ") }
Vasily
А при чем тут foreach?
Ayrat
ну в той ссылке что ты послал это был один из двух вариантов!
Vasily
Но пользуются for!!!!!11111
Ayrat
бля
Ayrat
я не знаю как сделать for и group by
Ayrat
я тупой наверное
Ayrat
ну точнее я вот сделал - мутабельная мапа и for
Vasily
for{ art<-listofArt if artRegex.findFirstMatchIn(art).isEmpty...
Vasily
groupby потом
Doge
Так. нужен код ревью от любителей скалировать. примитивная задача с кодварс есть массив строк вида "ABCD 20", где первая буква - категория, дальше неизвестное кол-во рандомных букв и цифра - кол-во товара в категории. Дан массив таких товаров и дан массив категорий. Надо найти кол-во товаров по данным категориям. Пример товары = Array("ABART 20", "CDXEF 50", "BKWRK 25", "BTSQZ 89", "DRTYM 60") категории = Array("A", "B", "C", "W") результат (A : 20) - (B : 114) - (C : 50) - (W : 0) мой говнокод val artRegex: Regex = raw"([A-Z])[A-Z]+ (\d+)".r def stockSummary(lstOfArt: Array[String], lstOfCat: Array[String]): String = { val catMap = lstOfArt.toStream.map(art => artRegex.findFirstMatchIn(art) match { case Some(matches) => (matches.group(1), matches.group(2).toInt) case None => throw new Exception(s"wrong art - $art") }) .groupBy(x => x._1) .map(x => { val sum = x._2.map(x => x._2).sum val cat = x._1 (cat, sum) }) .withDefaultValue(0) lstOfCat.toStream .map(cat => { val sum = catMap(cat) s"($cat : $sum)" }) .mkString(" - ") } он рабочий, но мне нужно знать как его улучшить, где тут подвохи, может я тут неоптимально чот делаю. И ещё фишки как упростить, укоротить и всё такое прочее. Не факт что я их заюзаю мне их просто надо знать, потому что я не шарю суммоню всех известных скалистов @vshapenko @DogeShibu @grishace @fvnever
Особо не вчитывался, пишу то, за что взгляд сходу зацепился. 1. Инстанс регекспа - это сразу unapplier, его можно использовать в паттерн матчах. 2. Вместо исключения лучше Either, если уж про ФП говорим 3. Сложные функции из map лучше перенести в отдельную локальную функцию.
Doge
1. не понял 2. Ща попробую, спасибо 3. Ща попробую, спасибо
val MyRegex = """(a+)""".r "aaaa" match { case MyRegex(as) => as case _ => "Some other string" }
Ayrat
ммм
Крылатый
Пацаны, го лепить идеальные блины. https://nplus1.ru/news/2019/06/17/perfect-blinchik
Ayrat
val MyRegex = """(a+)""".r "aaaa" match { case MyRegex(as) => as case _ => "Some other string" }
что-то не то получается lstOfArt.toStream.map(art => art match { case artRegex(cat, qty) => (cat, qty.toInt) case _ => throw new Exception(s"wrong art - $art") })
Ayrat
эта штука выдаёт не стрим, а тупль
Ayrat
я чот в местной системе типов не догоняю походу
Анна
@omgszer пиши на котлине 🤓
Ayrat
@omgszer пиши на котлине 🤓
Чот пока я скалой не впечатлился. Много неявных преобразований из нормальных типов в не пойми что. Подозреваю что в котлине та же трабла
Doge
что-то не то получается lstOfArt.toStream.map(art => art match { case artRegex(cat, qty) => (cat, qty.toInt) case _ => throw new Exception(s"wrong art - $art") })
val ArtRegex: Regex = raw"([A-Z])[A-Z]+ (\d+)".r object IsInt { def unapply(arg: String): Option[Int] = Try(arg.toInt).toOption } final case class Art(name: String, qty: Int) def stockSummary(lstOfArt: Array[String], lstOfCat: Array[String]): String = { val catMap = lstOfArt .collect { case ArtRegex(name, IsInt(int)) => Art(name, int) } .groupBy(_.name) .map { case (name, group) => (name, group.map(_.qty).sum) } .withDefaultValue(0) lstOfCat .map(cat => s"($cat : ${catMap(cat)})") .mkString(" - ") }
Doge
Это если относительно эквивалентными преобразованиями переписывать не особо вчитываясь.
Ayrat
Во, выглядит збс. Очень большое спасибо
Doge
Во, выглядит збс. Очень большое спасибо
Проверь на всякий случай, что работает. Я не проверял. Обрати ещё внимание на фукнцию collect и на тип PartialFunction, очень интересная штука, которая во многих случаях может пригодиться.
Vasily
Во, уже больше похоже на нечитаемый скала код
Vladislav
Во, выглядит збс. Очень большое спасибо
Надо было доге сразу пинговать
Ayrat
Надо было доге сразу пинговать
я его сразу и пинганул, но в начале я сам побарахтался
Ayrat
то есть не инпуты обрабатываются этим матчем
Doge
я правильно понимаю что здесь PartialFunction в том, что мы не все кейсы указываем и это валидно?
Да, именно оно. val partial : PartialFunction[Int, Int] = { case x if x > 5 => x } https://www.scala-lang.org/api/2.12.1/scala/PartialFunction.html
Doge
Никак не могу найти нормального туториала, который можно скинуть на эту тему.
Vasily
orElse цепляешь, как я понял
Ayrat
я хочу объявить кейз класс и деконстракт патерн сразу
Ayrat
но тогда сам патерн и конструктор конфликтуют
Doge
ещё вопрос. Как заставить это работать? case class Art(name: String, qty: Int) { def unapply(arg: String): Option[Int] = Try(arg.toInt).toOption }
Хмм... а чего именно хочешь добиться? Потому что тут у тебя деконструктор обьявлен у инстанса Art и именно для Int.
Ayrat
Хмм... а чего именно хочешь добиться? Потому что тут у тебя деконструктор обьявлен у инстанса Art и именно для Int.
Ну наприме я хочу создать некий тип у которого есть конструктор вида Art(string, int) и патерн для деконстракта из стринги в Option int
Ayrat
одноимённые
Ayrat
то есть к типу прицепить unapply в общем-то хочу
Ayrat
или их к типам нельзя прицеплять именно потому что неясно где конструктор, а где деконстракт?
Ayrat
Ахха. в кейз классе уже unapply генерится. Наверное это дичь
Viacheslav
Что-то первоапрельская шутка перестала быть шуткой
Vasily
Бля, Visual studio на маке - какой-то пздц
Vasily
На макоси, хорошо
Vasily
Там какой-то треш с чтением из консоли
Vasily
И выводом на консоль
Vladislav
Бля, Visual studio на маке - какой-то пздц
Там вроде все в параллелс в обычной студии сидят (или райдере)
Vladislav
Мои знакомые маководы так делали
Vasily
Какой треш?
Берешь пишешь программку, которая говорит "Введите число"
Vasily
И Console.ReadLine потом
Ayrat
@DogeShibu ешё вопрос. вот в такой конструкции, если lstOfCat массив - map сделает ещё один массив? lstOfCat .map(cat => s"($cat : ${catMap(cat)})") .mkString(" - ")
Ayrat
я подозреваю что да
Vasily
Надо байткод смотреть :)
Vasily
В скале же все call by name
Ayrat
ну по скалокоду должен сделать. там map у траверсаблЛайк вызывается
Doge
@DogeShibu ешё вопрос. вот в такой конструкции, если lstOfCat массив - map сделает ещё один массив? lstOfCat .map(cat => s"($cat : ${catMap(cat)})") .mkString(" - ")
Да, оно тупое и медленное. Поэтому в перформанс критикал местах лучше отказаться от этих методов и пойти честной хвостовой рекурсией, жабовскими стримами или мутабельными способами.
Vasily
ByteString
Ayrat
lstOfCat.toStream .map(cat => s"($cat : ${catMap(cat)})") .mkString(" - ")
Vasily
Вроде как
Vasily
Из того, что я в скала коде видел
Ayrat
и хопля, и перформас збс сразу стало
Doge
а недостаточно ли .toStream сделать?
toStream тоже не самая быстрая штука, если что.
Doge
Как и сами Stream'ы
Doge
а эт не жаба стримы разве?
Нет, это ленивый связвный список
Ayrat
Нет, это ленивый связвный список
нуууу......... стримы то есть?)))
Doge
нуууу......... стримы то есть?)))
Нет, жава стримы сделаны по другому, куда лучше по перформанс характеристикам.
Ayrat
Ща попробую на жаба стримах сделать (я вообще думал это они и есть лол)
Ayrat
@DogeShibu давай последний вопрос. У меня эта срань отказывается компилиться: import java.util import java.util.stream.Collectors import scala.util.Try import scala.util.matching.Regex object IsInt { def unapply(arg: String): Option[Int] = Try(arg.toInt).toOption } final case class Art(name: String, qty: Int) object StockList { val ArtRegex: Regex = raw"([A-Z])[A-Z]+ (\d+)".r def stockSummary(lstOfArt: Array[String], lstOfCat: Array[String]): String = { val catMap: util.Map[String, util.List[Art]] = util.Arrays.stream(lstOfArt) .map((article: String) => article match { case ArtRegex(cat, IsInt(qty)) => Art(cat, qty) case _ => throw new Exception(s"wrong article $article") } ) .collect(Collectors.groupingBy((x: Art) => x.name)) util.Arrays.stream(lstOfCat) .map(cat => { val allQtys = catMap.getOrDefault(cat, util.List.of()) val qtySum = allQtys.stream().map(_.qty).mapToInt(_).sum() s"($cat : $qtySum)" }) .collect(Collectors.joining(" - ")) } } ошибки вида Error:(20, 10) no type parameters for method map: (x$1: java.util.function.Function[_ >: String, _ <: R])java.util.stream.Stream[R] exist so that it can be applied to arguments (java.util.function.Function[String,Art]) --- because --- argument expression's type is not compatible with formal parameter type; found : java.util.function.Function[String,Art] required: java.util.function.Function[_ >: String, _ <: ?R] Note: String <: Any, but Java-defined trait Function is invariant in type T. You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10) .map((article: String) => если я убираю все тайп аннотейшны из лямбд или из val catMap: util.Map[String, util.List[Art]] =, он вообще везде ставит Nothing и всё валится. Я чот не понимаю наверное глобальное, да?
Ayrat
я попробовал жаба стримы, выглядят кошмарно конечно. надо постоянно приводить в стрим на любой чих. Для работы с разными стримами надо их надо конвертитьв IntStream, группировка через Collectors..