首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java 8流:从文本数据列表(List<String> list2)中计数元素的出现(List<String>list2)

Java 8流:从文本数据列表(List<String> list2)中计数元素的出现(List<String>list2)
EN

Stack Overflow用户
提问于 2020-02-27 23:34:14
回答 3查看 1.9K关注 0票数 5

投入:

代码语言:javascript
运行
复制
List<String> elements= new ArrayList<>();
        elements.add("Oranges");
        elements.add("Figs");
        elements.add("Mangoes");
        elements.add("Apple");

List<String> listofComments = new ArrayList<>();
        listofComments.add("Apples are better than Oranges");
        listofComments.add("I love Mangoes and Oranges");
        listofComments.add("I don't know like Figs. Mangoes are my favorites");
        listofComments.add("I love Mangoes and Apples");

输出:芒果,苹果,橘子,无花果->输出必须按元素出现次数的降序排列。如果元素看起来相等,则为no。它们必须按字母顺序排列。

我刚接触过Java 8,遇到了这个问题。我试着部分地解决它,但我无法解决它。有人能帮我找到更好的代码吗?

我的代码:

代码语言:javascript
运行
复制
Function<String, Map<String, Long>> function = f -> {
            Long count = listofComments.stream()
                    .filter(e -> e.toLowerCase().contains(f.toLowerCase())).count();
            Map<String, Long> map = new HashMap<>(); //creates map for every element. Is it right?
            map.put(f, count);
            return map;
        };

elements.stream().sorted().map(function).forEach(e-> System.out.print(e));

输出:{Apple=2}{Figs=1}{Mangoes=3}{Oranges=2}

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-02-28 08:51:34

在现实生活中,您必须考虑到,对任意数量的注释应用任意数量的匹配操作,在数量增加时可能会变得安静、昂贵,因此值得做一些准备:

代码语言:javascript
运行
复制
Map<String,Predicate<String>> filters = elements.stream()
    .sorted(String.CASE_INSENSITIVE_ORDER)
    .map(s -> Pattern.compile(s, Pattern.LITERAL|Pattern.CASE_INSENSITIVE))
    .collect(Collectors.toMap(Pattern::pattern, Pattern::asPredicate,
        (a,b) -> { throw new AssertionError("duplicates"); }, LinkedHashMap::new));

即使不执行正则匹配,Predicate类也是很有价值的。LITERALCASE_INSENSITIVE标志的组合支持具有预期语义的搜索,而无需将整个字符串转换为小写(顺便说一句,这并不足以满足所有可能的情况)。对于这种匹配,准备工作将包括为Boyer-Moore算法构建必要的数据结构,以便在内部进行更有效的搜索。

这张地图可以重复使用。

对于你的具体任务,一种使用它的方法是

代码语言:javascript
运行
复制
filters.entrySet().stream()
    .map(e -> Map.entry(e.getKey(), listofComments.stream().filter(e.getValue()).count()))
    .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
    .forEachOrdered(e -> System.out.printf("%-7s%3d%n", e.getKey(), e.getValue()));

它将为示例数据打印如下:

代码语言:javascript
运行
复制
Mangoes  3
Apple    2
Oranges  2
Figs     1

请注意,filters映射已经按字母顺序排序,第二个流操作的sorted对于具有定义的遭遇顺序的流是https://en.wikipedia.org/wiki/Sorting_algorithm#Stability,因此它只需要按事件排序,具有相同元素的条目将保持相对顺序,这是源映射中的字母顺序。

Map.entry(…)需要JavaAversion9或更高版本。对于Java 8,您必须使用以下内容

取而代之的是new AbstractMap.SimpleEntry(…)

票数 3
EN

Stack Overflow用户

发布于 2020-02-28 02:58:36

您仍然可以修改您的函数来存储Map.Entry,而不是完整的Map

代码语言:javascript
运行
复制
Function<String, Map.Entry<String, Long>> function = f -> Map.entry(f, listOfComments.stream()
        .filter(e -> e.toLowerCase().contains(f.toLowerCase())).count());

然后在执行终端操作(在您的示例中为forEach打印)之前,对这些条目进行排序。

代码语言:javascript
运行
复制
elements.stream()
        .map(function)
        .sorted(Comparator.comparing(Map.Entry<String, Long>::getValue)
                .reversed().thenComparing(Map.Entry::getKey))
        .forEach(System.out::println);

然后,这将为您提供以下输出:

代码语言:javascript
运行
复制
Mangoes=3
Apples=2
Oranges=2
Figs=1
票数 1
EN

Stack Overflow用户

发布于 2020-02-28 00:18:09

第一件事是声明一个额外的类。它将保存元素并计数:

代码语言:javascript
运行
复制
class ElementWithCount {
    private final String element;
    private final long count;

    ElementWithCount(String element, long count) {
        this.element = element;
        this.count = count;
    }

    String element() {
        return element;
    }

    long count() {
        return count;
    }
}

要计算count,让我们声明一个额外的函数:

代码语言:javascript
运行
复制
static long getElementCount(List<String> listOfComments, String element) {
    return listOfComments.stream()
            .filter(comment -> comment.contains(element))
            .count();
}

因此,要找到结果,我们需要将元素流转换为ElementWithCount对象流,然后按计数对该流进行排序,然后将其转换回元素流,并将其收集到结果列表中。

为了简化这项任务,让我们将比较器定义为一个单独的变量:

代码语言:javascript
运行
复制
Comparator<ElementWithCount> comparator = Comparator
        .comparing(ElementWithCount::count).reversed()
        .thenComparing(ElementWithCount::element);

现在,当所有部分都准备就绪时,最后的计算就很容易了:

代码语言:javascript
运行
复制
List<String> result = elements.stream()
        .map(element -> new ElementWithCount(element, getElementCount(listOfComments, element)))
        .sorted(comparator)
        .map(ElementWithCount::element)
        .collect(Collectors.toList());

您可以使用Map.Entry代替单独的类和内联getElementCount,因此它将是“单行”解决方案:

代码语言:javascript
运行
复制
List<String> result = elements.stream()
        .map(element ->
                new AbstractMap.SimpleImmutableEntry<>(element,
                        listOfComments.stream()
                                .filter(comment -> comment.contains(element))
                                .count()))
        .sorted(Map.Entry.<String, Long>comparingByValue().reversed().thenComparing(Map.Entry.comparingByKey()))
        .map(Map.Entry::getKey)
        .collect(Collectors.toList());

但是在这种形式下很难理解,所以我建议把它分成逻辑部分。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60443274

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档