最近,我们在jOOλ0.9.9中发布了有关超棒的窗口函数支持的文章 ,我相信这是对我们所做的库的最佳补充。
今天,我们将在一个用例中研究窗口函数的出色应用,该用例受到以下堆栈溢出问题Sean Nguyen的启发:
如何从Java 8流(如grep)匹配前后获取行?
我有一个文本文件,其中有很多字符串行。 如果我想在grep中找到匹配之前和之后的行,我会这样做:
grep -A 10 -B 10 "ABC" myfile.txt
如何使用流在Java 8中实现等效功能?
所以问题是:
如何使用流在Java 8中实现等效功能?
好吧,unix shell及其各种“可点入”命令是唯一比窗口函数更强大(更神秘)的东西。 能够grep输入文件中的某个字符串,然后显示几行的“窗口”非常有用。
但是,有了jOOλ0.9.9,我们也可以在Java 8中非常容易地做到这一点 。 考虑一下这个小片段:
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: .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(或其他通用语言)编写函数比较简单,因为涉及的语法较少。 我们可以轻松地在窗口框架上进行聚合,以收集“滞后”和“领先”匹配的通用行数。 考虑以下替代方法:
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"))
我们得到的输出是这样的:
-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启发的。
通过模仿SQL的窗口函数,在内存数据流上进行强大的操作时,只有很小的认知摩擦。
在以下文章中了解有关窗口函数的更多信息:
- 可能最酷的SQL功能:窗口函数
- 使用此整齐的窗口函数技巧来计算时间序列中的时差
- 如何在SQL中找到最长的连续事件系列
- 不要错过具有FIRST_VALUE(),LAST_VALUE(),LEAD()和LAG()的超凡SQL能力
- ROW_NUMBER(),RANK()和DENSE_RANK()之间的区别
翻译自: https://www.javacodegeeks.com/2016/01/pattern-match-files-display-adjacent-lines-java.html