Недавно мы опубликовали нашу статью о потрясающей поддержке оконных функций в jOOλ 0.9.9 , которая, я считаю, является одним из лучших дополнений к библиотеке, которые мы когда-либо делали.
Сегодня мы рассмотрим удивительное применение оконных функций в сценарии использования, вдохновленном этим вопросом переполнения стека Шон Нгуен:
Как получить строки до и после сопоставления из потока Java 8, как grep?
У меня есть текстовые файлы, в которых много строк. Если я хочу найти строки до и после сопоставления в grep, я сделаю так:
1grep-A 10 -B 10"ABC"myfile.txtКак я могу реализовать эквивалент в Java 8, используя потоки?
Итак, вопрос:
Как я могу реализовать эквивалент в Java 8, используя потоки?

Однако с jOOλ 0.9.9 мы можем сделать это очень легко и в Java 8 . Посмотрите на этот маленький фрагмент:
|
01
02
03
04
05
06
07
08
09
10
11
|
Seq.seq(Files.readAllLines(Paths.get( new File("/path/to/Example.java").toURI()))) .window() .filter(w -> w.value().contains("ABC")) .forEach(w -> { System.out.println(); System.out.println("-1:" + w.lag().orElse("")); System.out.println(" 0:" + w.value()); System.out.println("+1:" + w.lead().orElse("")); // ABC: Just checking }); |
Эта программа выведет:
|
1
2
3
4
5
6
7
|
-1: .window() 0: .filter(w -> w.value().contains("ABC"))+1: .forEach(w -> {-1: System.out.println("+1:" + w.lead().orElse("")); 0: // ABC: Just checking+1: }); |
Итак, я запустил программу сам и нашел все строки, которые соответствуют «ABC», плюс предыдущие строки («lagging» / lag() ) и следующие строки ( lead() / lead() ). Эти функции lead() и lag() работают так же, как их SQL-эквиваленты .
Но в отличие от SQL, составление функций в Java (или других языках общего назначения) немного проще, так как здесь меньше синтаксического беспорядка. Мы можем легко выполнить агрегацию по рамке окна, чтобы собрать общее количество строк, «отстающих» и «ведущих» совпадение. Рассмотрим следующую альтернативу:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
int lower = -5;int upper = 5; Seq.seq(Files.readAllLines(Paths.get( new File("/path/to/Example.java").toURI()))) .window(lower, upper) .filter(w -> w.value().contains("ABC")) .map(w -> w.window() .zipWithIndex() .map(t -> tuple(t.v1, t.v2 + lower)) .map(t -> (t.v2 > 0 ? "+" : t.v2 == 0 ? " " : "") + t.v2 + ":" + t.v1) .toString("\n")) |
И результат, который мы получаем:
|
01
02
03
04
05
06
07
08
09
10
11
|
-5:int upper = 5;-4: -3:Seq.seq(Files.readAllLines(Paths.get(-2: new File("/path/to/Example.java").toURI())))-1: .window(lower, upper) 0: .filter(w -> w.value().contains("ABC"))+1: .map(w -> w.window()+2: .zipWithIndex()+3: .map(t -> tuple(t.v1, t.v2 + lower))+4: .map(t -> (t.v2 > 0+5: ? "+" |
Может ли это быть более кратким? Я так не думаю. Большая часть логики выше просто генерировала индекс рядом со строкой.
Вывод
Оконные функции очень мощные. Недавнее обсуждение reddit о нашей предыдущей статье о поддержке оконных функций jOOλ показало, что другие языки также поддерживают примитивы для создания аналогичной функциональности. Но обычно эти строительные блоки не так лаконичны, как те, что представлены в jOOλ, вдохновленные SQL.
Благодаря jOOλ, имитирующему оконные функции SQL, при составлении мощных операций в потоках данных в памяти практически не возникает когнитивных трений.
Узнайте больше об оконных функциях в этих статьях здесь:
- Вероятно, самая крутая особенность SQL: оконные функции
- Используйте этот аккуратный трюк с функцией окна для расчета разницы во времени во временном ряду
- Как найти самую длинную последовательность событий в SQL
- Не упустите возможности SQL Power с FIRST_VALUE (), LAST_VALUE (), LEAD () и LAG ()
- Разница между ROW_NUMBER (), RANK () и DENSE_RANK ()
| Ссылка: | Как сопоставлять шаблоны и отображать смежные строки в Java от нашего партнера по JCG Лукаса Эдера из блога JAVA, SQL и AND JOOQ . |