Java流:将单个数字映射到范围内

6

我希望将数字对转化为整数范围,以便我可以在其上执行函数。 例如,以下每行:

1-4
5-6
1-2
4-7

需要转换为数组,即:[1,2,3,4]。 我的目标是计算最常见的数字。 我试图像单词计数示例一样完成它,但问题在于如何从每行的两个数字创建范围流?

Path path = Paths.get(args[0]);
    Map<String, Long> wordCount = Files.lines(path)
            .flatMap(line -> Arrays.stream(line.trim().split("-")))
            .
            .map(word -> word.replaceAll("[^a-zA-Z]", "").toLowerCase().trim())
            .filter(num -> num.length() > 0)
            .map(number -> new SimpleEntry<>(number, 1))
            .collect(Collectors.groupingBy(SimpleEntry::getKey, Collectors.counting()));

4
https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html#rangeClosed-int-int- - JB Nizet
是的,但是 .flatMap(line -> Arrays.stream(line.trim().split("-"))) .flatMap(x, y -> IntStream.rangeClosed(x, y).boxed().mapToObj(j -> new Pair<>(i, j))) 不起作用。 - user1450410
这只是代码的一部分...简而言之 - 你知道我是否对每行的2个数字执行一个函数吗? - user1450410
2个回答

4
以下管道将每行按-分割,然后使用IntStream创建两者之间的数字范围。结果是所有这些内部整数的扁平流,随后是计数分组(数字)。然后在此映射的值上找到最大“计数”。
String s = "1-4\n" + "5-6\n" + "1-2\n" + "4-7"; //simpler version with inline text

Optional<Entry<Integer, Long>> result = 
    Stream.of(s.split("\n")) //replace with Files.lines(path) for real stream
    .map(line -> line.split("-"))
    .map(array -> new int[] { Integer.parseInt(array[0].trim()), 
                              Integer.parseInt(array[1].trim()) })
    .map(array -> IntStream.rangeClosed(array[0], array[1]))
    .flatMapToInt(Function.identity())
    .boxed()
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
    .entrySet()
    .stream()
    .max(Comparator.comparingLong(Entry::getValue));

result.ifPresent(System.out::println);

使用你的示例数据,它将打印1=21出现了2次)- 有许多值恰好出现两次。

3
无需使用.map(array -> IntStream.rangeClosed(array[0], array[1])) .flatMapToInt(Function.identity()),直接使用.flatMapToInt(array -> IntStream.rangeClosed(array[0], array[1]))即可。 - Holger

0
如果您想要查看所有数字的最大频率,可以像这样完成:
private static List<Integer> findMaxOccurs(String... ranges) {
    return Optional
        .ofNullable(
            Arrays.stream(ranges)
                  .map(r -> r.split("-"))
                  .flatMap(r -> IntStream.rangeClosed(Integer.parseInt(r[0]),
                                                      Integer.parseInt(r[1]))
                                         .boxed())
                  .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                  // We now have Map<Integer, Long> mapping Number to Frequency
                  .entrySet()
                  .stream()
                  .collect(Collectors.groupingBy(Entry::getValue, TreeMap::new,
                              Collectors.mapping(Entry::getKey, Collectors.toList())))
                  // We now have TreeMap<Long, List<Integer>> mapping Frequency to Numbers
                  .lastEntry()
        )
        .map(Entry::getValue)
        .orElse(Collections.emptyList());
}

测试

System.out.println(findMaxOccurs("1-4", "5-6", "1-2", "4-7"));

输出

[1, 2, 4, 5, 6]

如果你也想知道那些数的频率,最好将其拆分成两个方法:

private static Entry<Long, List<Integer>> findMaxOccurring(String... ranges) {
    return Arrays.stream(ranges)
                 .map(r -> r.split("-"))
                 .flatMap(r -> IntStream.rangeClosed(Integer.parseInt(r[0]),
                                                     Integer.parseInt(r[1])).boxed())
                 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                 // We now have Map<Integer, Long> mapping Number to Frequency
                 .entrySet()
                 .stream()
                 .collect(Collectors.groupingBy(Entry::getValue, TreeMap::new,
                             Collectors.mapping(Entry::getKey, Collectors.toList())))
                 // We now have TreeMap<Long, List<Integer>> mapping Frequency to Numbers
                 .lastEntry();
}

private static List<Integer> findMaxOccurringNumbers(String... ranges) {
    return Optional.ofNullable(findMaxOccurring(ranges))
                   .map(Entry::getValue)
                   .orElse(Collections.emptyList());
}

测试

System.out.println(findMaxOccurring("1-4", "5-6", "1-2", "4-7"));
System.out.println(findMaxOccurringNumbers("1-4", "5-6", "1-2", "4-7"));

输出

2=[1, 2, 4, 5, 6]
[1, 2, 4, 5, 6]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接