Гость
Map
Форумы / Java [игнор отключен] [закрыт для гостей] / Scala : поджать списочек. / 19 сообщений из 19, страница 1 из 1
08.02.2021, 14:45
    #40043298
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
Вот приплыла идея.
Есть такой монотонный список чисал. Заданный в оригинале строкой.

Код: sql
1.
'12,13,14,15,16,21,22,23,48,51,52,53'



Надо его "поджать". Сделать нечто вроде.

Код: sql
1.
'12-15,21-23,48,51-53'



Поскольку наркотик ФП уже проник в меня я думаю как-бы я это решал.
Классическое императивное решение - это создать некий автомат с состоянием
который пробежит от начала строки до конца и будет формировать структуры
типа Integer или Range на выходе. Но тут надо смотреть на 2-3 шага вперед.
А это неудобно в автоматах. +Еще эти пограничные кейсы. О которых думать противно.

Хочется уже это сделать на reduce/fold/collect.
...
Рейтинг: 0 / 0
08.02.2021, 15:04
    #40043314
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
mayton
Но тут надо смотреть на 2-3 шага вперед

после получения очередной лексемы из потока вперёд смотреть незачем
...
Рейтинг: 0 / 0
08.02.2021, 15:24
    #40043324
Leonid Kudryavtsev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
Вроде вообще ни один парсер никогда "вперед" не смотрит. Нормальный парсер хранит одно (обычно) предыдущее значение и изредко его откатывает.

похоже mayton'у "наркотик ФП уже проник в меня" настолько, что он конечные автоматы позабыл напрочь )))
...
Рейтинг: 0 / 0
08.02.2021, 15:26
    #40043325
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
Чортовы наркотики
...
Рейтинг: 0 / 0
08.02.2021, 15:56
    #40043340
chpasha
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
про скалу не знаю, если где натупил, соррян

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
public List<Range> compact(String values)
	{
		String[] strings = values.split(",");
		Range currentRange = null;
		List<Range> ranges = new ArrayList<>();
		for (String string : strings)
		{
			Integer currentValue = Integer.parseInt(string);
			if (currentRange == null || currentValue - currentRange.to > 1)
			{
				currentRange = new Range(currentValue, currentValue);
				ranges.add(currentRange);
			}
			else
			{
				currentRange.to = currentValue;
			}

		}
		return ranges;
	}

	public List<Range> compactFunc(String values)
	{
		String[] strings = values.split(",");
		return Arrays.stream(strings)
					 .map(Integer::valueOf)
					 .collect(ArrayList::new, this::accumulate, (l1, l2) -> {});
	}

	private void accumulate(List<Range> range, Integer val)
	{
		if (range.isEmpty() || val - range.get(range.size() - 1).to > 1)
		{
			range.add(new Range(val, val));
		}
		else
		{
			range.get(range.size() - 1).to = val;
		}
	}


compact("12,13,14,15,16,21,22,23,48,51,52,53").forEach(System.out::println);

compactFunc("12,13,14,15,16,21,22,23,48,51,52,53").forEach(System.out::println);


12-16
21-23
48
51-53
...
Рейтинг: 0 / 0
08.02.2021, 16:20
    #40043359
забыл ник
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
object D extends App {
  val str = "12,13,14,15,16,21,22,23,48,51,52,53"
  case class Range(start: Int, end: Int)
  private def handleNumber(num: Int, ranges: List[Range]) = {
    val latest = ranges.headOption
    val openStart = latest.map(_.start).getOrElse(-1)
    val openEnd = latest.map(_.end).getOrElse(-1)
    if (openStart == -1) {
      List(Range(start = num, end = num))
    } else if (num == openEnd + 1) {
      latest.get.copy(end = num) +: ranges.tail
    } else {
      Range(start = num, end = num) +: ranges
    }
  }

  val result = str.split(",").map(_.trim).foldLeft(List.empty[Range]){
    (accum, num) => handleNumber(num.toInt, accum)
  }.reverse
  println(result)
}



По факту та же стейт машина - вид в профиль
...
Рейтинг: 0 / 0
08.02.2021, 16:23
    #40043361
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
chpasha, спасибо. А можно ли как-то еще уменьшить объем кода? Просто то императивное решение которое
я себе представлял все еще компактнее чем решение с stream/collect.
...
Рейтинг: 0 / 0
08.02.2021, 16:30
    #40043365
забыл ник
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
Если совсем буков жалко то вот так -

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
object D extends App {
  val str = "12,13,14,15,16,21,22,23,48,51,52,53"
  case class Range(start: Int, end: Int)
  private def handleNumber(ranges: List[Range], num: Int) = {
    val latest = ranges.headOption
    val openEnd = latest.map(_.end).getOrElse(-1)
    if (openEnd == -1) {
      List(Range(num, num))
    } else if (num == openEnd + 1) {
      latest.get.copy(end = num) +: ranges.tail
    } else {
      Range(num, num) +: ranges
    }
  }

  val result = str.split(",").map(_.trim.toInt).foldLeft(List.empty[Range])(handleNumber).reverse
  println(result)
}
...
Рейтинг: 0 / 0
08.02.2021, 16:36
    #40043367
chpasha
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
mayton
компактнее чем решение с stream/collect.
там же оба решения, ты заметил?
я не знаю как еще упростить - весь код это по сути только метод accumulate, остальное предварительные расшаркивания
...
Рейтинг: 0 / 0
08.02.2021, 16:38
    #40043370
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
забыл ник, паша,

спасибо друзья.
...
Рейтинг: 0 / 0
08.02.2021, 17:08
    #40043392
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
(раскачиваясь взад-вперед)

Не нравится мне этот метод.

Код: java
1.
private def handleNumber(ranges: List[Range], num: Int) = {


Он написан ... как бы это сказать... не в духе ФП. Он - модифицирует свой собственный аргумент.
Возможно это контракт коллектора?

Можно ли переписать с reduce? Понимаю что накладные будут.

Ну ... это так. Ворчу просто.

Ворчун я.
...
Рейтинг: 0 / 0
08.02.2021, 17:20
    #40043398
SpringMan
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
Вообще можно как-то так, если память/процессор не жалко:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
  val result = "12,13,14,15,16,21,22,23,48,51,52,53".split(",")
    .map(_.toInt)
    .zipWithIndex
    .groupBy { case (value, index) => value - index }
    .values.toSeq
    .sortBy(_.head._1)
    .map(pairs => pairs.map(_._1))
    .map(arrays => if (arrays.length != 1) s"${arrays.head}-${arrays.last}" else s"${arrays.head}")
    .mkString(",")
  println(result)
...
Рейтинг: 0 / 0
08.02.2021, 17:34
    #40043405
забыл ник
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
mayton

Он написан ... как бы это сказать... не в духе ФП. Он - модифицирует свой собственный аргумент.

Нет, там ничего не меняется. Объекты новые создаются, это да, но по минимуму. Самое что ни на есть тру ФП

mayton

Можно ли переписать с reduce?

Можно, но это тот же fold. И оба в конце концов сводятся к рекурсивному методу handleNumber

mayton

Понимаю что накладные будут.

На самом деле не такие огромные, списки не копируются а элементы хвоста и более того шарятся, оставаясь при этом иммутабл
...
Рейтинг: 0 / 0
08.02.2021, 17:48
    #40043419
SpringMan
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
Вариация на тему ренжей, только через Seq-и:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
  val result = "12,13,14,15,16,21,22,23,48,51,52,53".split(",")
    .map(_.toInt)
    .foldLeft(Seq[Seq[Int]]()) { case (total, currentValue) =>
      if (total.lastOption.flatMap(_.lastOption).exists(_ + 1 == currentValue)) {
        total.init :+ (Seq(total.last.head) :+ currentValue)
      } else {
        total :+ Seq(currentValue)
      }
    }
    .map(array => if (array.length != 1) s"${array.head}-${array.last}" else s"${array.head}")
    .mkString(",")
  println(result)
...
Рейтинг: 0 / 0
08.02.2021, 17:53
    #40043425
SpringMan
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
Тут в общем выбор: иммутабельность или затраты на память
...
Рейтинг: 0 / 0
09.02.2021, 01:46
    #40043505
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
SpringMan, спасибо. Уже есть пища для размышлений.
...
Рейтинг: 0 / 0
10.02.2021, 19:25
    #40044142
andreykaT
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
кто то решил прокачать скилы гадилити?
...
Рейтинг: 0 / 0
10.02.2021, 19:29
    #40044146
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
Я не знаю что это.

Просто, в тему Прохоровских лотерейных билетов.
...
Рейтинг: 0 / 0
10.02.2021, 19:36
    #40044148
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Scala : поджать списочек.
Отчот большой был. Я хотел его "пожать".

Как Дима из команды "Так-То". Кто-то говорит телефон посеял. А я его "пожал".
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / Scala : поджать списочек. / 19 сообщений из 19, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]