用 lambda 表达式 java 实现计数变量
Implement counting variable with lambda expression java
我有一个关于 lambda 表达式的问题。我有一个 class 对,它应该包含一个字符串和一个整数。
Pair 从文件中获取字符串。
并且 int 代表行号。
到目前为止我有这个:
Stream<String> lineNumbers = Files.lines(Paths.get(fileName));
List<Integer> posStream = Stream.iterate(0, x -> x + 1).limit(lineNumbers.count()).collect(Collectors.toList());
lineNumbers.close();
Stream<String> line = Files.lines(Paths.get(fileName));
List<Pair> pairs = line.map((f) -> new Pair<>(f,1))
.collect(Collectors.toList());
pairs.forEach(f -> System.out.println(f.toString()));
line.close();
现在如何将文件编号输入对?
是否有可以执行此操作的 lambda 表达式?或者我还需要其他东西吗?
int cnt = 1;
List<Pair> pairs = line.map((f) -> new Pair<>(f,cnt++))
.collect(Collectors.toList());
我还没有尝试过,但可能会奏效。
另一种实用的方法是使用整数生成器压缩您的流列表
(我可以看到 java8 还没有,但它本质上是将两个列表的每个单元格合并成对列表,因此很容易实现)
您可以在 java8 here
中查看生成器示例
有几种方法可以做到这一点。 建议的计数器技术可以如下实现,使用 AtomicInteger
作为可变计数器对象并假设明显的 Pair
class:
List<Pair> getPairs1() throws IOException {
AtomicInteger counter = new AtomicInteger(0);
try (Stream<String> lines = Files.lines(Paths.get(FILENAME))) {
return lines.parallel()
.map(line -> new Pair(line, counter.incrementAndGet()))
.collect(toList());
}
}
问题是,如果流是 运行 并行的,计数器将不会按照与读取行相同的顺序递增!如果您的文件有几千行,就会发生这种情况。 Files.lines
流源将对成串的行进行批处理并将它们分派给多个线程,然后这些线程将并行编号它们的批次,交错调用它们对 incrementAndGet()
。因此,行不会按顺序编号。如果你能保证你的流永远不会 运行 并行,它就会起作用,但是编写可能 return 顺序与并行不同结果的流通常是一个坏主意。
这是另一种方法。由于无论如何都要将所有行读入内存,因此只需将它们全部读入列表即可。然后用流给它们编号:
static List<Pair> getPairs2() throws IOException {
List<String> lines = Files.readAllLines(Paths.get(FILENAME));
return IntStream.range(0, lines.size())
.parallel()
.mapToObj(i -> new Pair(lines.get(i), i+1))
.collect(toList());
}
我有一个关于 lambda 表达式的问题。我有一个 class 对,它应该包含一个字符串和一个整数。
Pair 从文件中获取字符串。 并且 int 代表行号。 到目前为止我有这个:
Stream<String> lineNumbers = Files.lines(Paths.get(fileName));
List<Integer> posStream = Stream.iterate(0, x -> x + 1).limit(lineNumbers.count()).collect(Collectors.toList());
lineNumbers.close();
Stream<String> line = Files.lines(Paths.get(fileName));
List<Pair> pairs = line.map((f) -> new Pair<>(f,1))
.collect(Collectors.toList());
pairs.forEach(f -> System.out.println(f.toString()));
line.close();
现在如何将文件编号输入对? 是否有可以执行此操作的 lambda 表达式?或者我还需要其他东西吗?
int cnt = 1;
List<Pair> pairs = line.map((f) -> new Pair<>(f,cnt++))
.collect(Collectors.toList());
我还没有尝试过,但可能会奏效。
另一种实用的方法是使用整数生成器压缩您的流列表
(我可以看到 java8 还没有,但它本质上是将两个列表的每个单元格合并成对列表,因此很容易实现)
您可以在 java8 here
中查看生成器示例有几种方法可以做到这一点。 AtomicInteger
作为可变计数器对象并假设明显的 Pair
class:
List<Pair> getPairs1() throws IOException {
AtomicInteger counter = new AtomicInteger(0);
try (Stream<String> lines = Files.lines(Paths.get(FILENAME))) {
return lines.parallel()
.map(line -> new Pair(line, counter.incrementAndGet()))
.collect(toList());
}
}
问题是,如果流是 运行 并行的,计数器将不会按照与读取行相同的顺序递增!如果您的文件有几千行,就会发生这种情况。 Files.lines
流源将对成串的行进行批处理并将它们分派给多个线程,然后这些线程将并行编号它们的批次,交错调用它们对 incrementAndGet()
。因此,行不会按顺序编号。如果你能保证你的流永远不会 运行 并行,它就会起作用,但是编写可能 return 顺序与并行不同结果的流通常是一个坏主意。
这是另一种方法。由于无论如何都要将所有行读入内存,因此只需将它们全部读入列表即可。然后用流给它们编号:
static List<Pair> getPairs2() throws IOException {
List<String> lines = Files.readAllLines(Paths.get(FILENAME));
return IntStream.range(0, lines.size())
.parallel()
.mapToObj(i -> new Pair(lines.get(i), i+1))
.collect(toList());
}