【问题标题】:Get line-numbers in which a certain word/text occurs获取某个单词/文本出现的行号
【发布时间】:2015-04-30 13:14:59
【问题描述】:

我有什么:我有一个文件可以逐行读取。这些行不计入文件中。

我想做的事:我想计算 ONE 流中的每一行,并只返回特定文本出现的数字。

我目前所拥有的:

public static Integer findLineNums(String word)
        throws IOException {

    final Map<String, Integer> map = new HashMap<>();
    final List<String> lines = Files.lines(Paths.get(PATH)).collect(Collectors.toList());                 
    IntStream.rangeClosed(0, lines.size()-1).forEach(f -> map.put(lines.get(f), f+1));

    return map.get(word);
}

问题:我怎样才能只使用一个单一的流来做到这一点?

编辑的问题:我想在 Stream 中做所有事情,这也包括累积到一个列表中。

最好的情况是这样的:

Files.lines(Paths.get(PATH)).superAwesomeStreamFuncs().collect(Collectors.toList());

编辑:在我的情况下,我只会返回一个整数,但我想得到一个整数列表之类的东西。

【问题讨论】:

    标签: java stream


    【解决方案1】:

    这行得通:

    int[] i = new int[]{0}; // trick to make it final
    List<Integer> hits = <your stream>
      .map(s -> s.contains(word) ? ++i[0] : - ++i[0])
      .filter(n -> n > 0)
      .collect(Collectors.toList());
    

    这里的主要“技巧”是使用数组,它的引用不会改变(即它“实际上是最终的”,但它允许我们改变它的(唯一的)元素 作为计数器,无论如何它都会内联递增。快速过滤器会抛出不匹配项。


    一些测试代码:

    String word = "foo";
    int[] i = new int[]{0};
    List<Integer> hits = Stream.of("foo", "bar", "foobar")
    .map(s -> s.contains(word) ? ++i[0] : - ++i[0])
    .filter(n -> n > 0)
    .collect(Collectors.toList());
    System.out.println(hits);
    

    输出:

    [1, 3]
    

    【讨论】:

    • 不错,使用流函数在数组中进行迭代似乎有点棘手,不过我喜欢你的解决方案。
    【解决方案2】:

    跟随 sn-p 将创建一个List&lt;Integer&gt;,其中包含包含单词的行

    String word = "foo";
    List<Integer> matchedLines = new ArrayList<>();
    final List<String> lines = Files.readAllLines(Paths.get("word_list.txt"));
    IntStream.rangeClosed(0, lines.size() - 1).forEach(f -> {
        if (lines.get(f).contains(word)) {
            matchedLines.add(++f);
        }
    });
    System.out.println("matchedLines = " + matchedLines);
    

    假设文件word_list.txt

    foo
    bar
    baz
    foobar
    barfoo
    

    输出是

    matchedLines = [1, 4, 5]
    

    编辑要使用单个流解决它,请创建自定义Consumer

    public class MatchingLines {
    
        static class MatchConsumer implements Consumer<String> {
            private int count = 0;
            private final List<Integer> matchedLines = new ArrayList<>();
            private final String word;
    
            MatchConsumer(String word) {
                this.word = word;
            }
    
            @Override
            public void accept(String line) {
                count++;
                if (line.contains(this.word)) {
                    matchedLines.add(count);
                }
            }
    
            public List<Integer> getResult() {
                return matchedLines;
            }
        }
    
        public static void main(String[] args) throws IOException {
            MatchConsumer matchConsumer = new MatchConsumer("foo");
            Files.lines(Paths.get("word_list.txt")).forEach(matchConsumer);
            System.out.println("matchedLines = " + matchConsumer.getResult());
        }
    }
    

    【讨论】:

    • 这解决了列表部分,但是在一个流中做所有事情呢?如何迭代流中间的元素?编辑:我也想在流中做所有事情,所以在这种情况下,我也想在 ArrayList 中累积流。
    • @SklogW 看看添加的示例。我坚持你只想要一个流中的整数而不是所有东西。
    【解决方案3】:

    此方法返回由其在文件中的编号映射的行。

    public static Map<String, Integer> findLineNums(Path path, String word) throws IOException {
    
            final Map<String, Integer> map = new HashMap<>();
            int lineNumber = 0;
            Pattern pattern = Pattern.compile("\\b" + word + "\\b");
    
            try (BufferedReader reader = Files.newBufferedReader(path)) {
                String line = null;
                while ((line = reader.readLine()) != null) {
                    lineNumber++;
                    if (pattern.matcher(line).find()) {
                        map.put(line, lineNumber);
                    }
                }
            }
            for (String line : map.keySet()) {
                Integer lineIndex = map.get(line);
                System.out.printf("%d  %s\n", lineIndex, line);
            }
            return map;
        }
    

    BufferedReaderFiles.lines 流一样逐行读取文件。

    【讨论】:

    • 这根本不使用 Streams。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-17
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    • 1970-01-01
    • 2016-02-17
    相关资源
    最近更新 更多