首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不应用嵌套列表的Java流的限制()

不应用嵌套列表的Java流的限制()
EN

Stack Overflow用户
提问于 2017-09-14 17:16:11
回答 2查看 644关注 0票数 1

我有一个Category列表,每个列表都有一个Phrase的列表,我希望将这个列表减少到短语数量最少的类别,将短语的数量限制在Y上,然后为所有匹配的类别和短语创建一个新的对象CategoryAndPhrase

这似乎是Java 8流API的一个很好的候选者,但我没有得到预期的结果。这是我的代码,每行旁边都有注释,解释我想要达到的目标。在这个问题的末尾有一个完整的代码示例。

代码语言:javascript
复制
List<CategoryAndPhrase> categoriesAndPhrases = allCategories.stream()
            .filter(category -> category.getPhrases().size() >= numberOfPhrasesPerCategory) // remove the categories which don't have enough phrases to match our criteria
            .limit(numberOfCategories) // reduce the list to the number categories we require
            .map(Category::getPhrases) // change the stream so it is now a stream of the phrases for the selected categories
            .limit(numberOfPhrasesPerCategory) // reduce the phrases for each of the selected categories to the number of phrases we require
            .flatMap(List::stream)
            .map(phrase -> new CategoryAndPhrase(phrase.getCategory(), phrase.getName())) // create the new object for each of the selected phrases
            .collect(Collectors.toCollection(ArrayList::new));

示例

输入数据:

  • 运动队<-- Category
    • 曼彻斯特联队<-- Phrase
    • 阿森纳
    • 斯旺西市
    • 哈特尔普尔联队

  • 问候
    • 你好

  • 再见,
    • 再见
    • 再见
    • Au再见

  • 语言
    • 英语
    • 意大利语
    • 法语
    • 德语

类别数:2

每类短语数:3

预期产出:

  • 类别:运动队,短语:曼联
  • 类别:运动队,短语:阿森纳
  • 类别:运动队,短语:斯旺西
  • 类别:再见,短语:再见
  • 类别:再见,短语:再见
  • 类别:再见,短语:再见

实际产出:

  • 类别:运动队,短语:曼联
  • 类别:运动队,短语:阿森纳
  • 类别:运动队,短语:斯旺西
  • 类别:运动队,短语:哈特莱普尔联合
  • 类别:再见,短语:再见
  • 类别:再见,短语:再见
  • 类别:再见,短语:再见

请注意,第四运动队包括在内,即使我只要求每个类别3个短语。

第一个limit()操作看起来是正确的,因为只有两个类别返回,尽管三个符合至少有三个短语的标准,但是第二个不像预期的那样工作。

我哪里出问题了?

全码

您还可以找到这段代码论JDoodle

代码语言:javascript
复制
import java.util.List;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.LinkedList;
import java.util.ArrayList;

public class MyClass {
    public static void main(String args[]) {
        new MyClass().run();
    }

    public void run() {
        Phrase sportsTeam1 = new Phrase("Manchester United", "Sports Teams");
        Phrase sportsTeam2 = new Phrase("Arsenal", "Sports Teams");
        Phrase sportsTeam3 = new Phrase("Swansea", "Sports Teams");
        Phrase sportsTeam4 = new Phrase("Hartlepool United", "Sports Teams");
        Category sportsTeams = new Category("Sports Teams", Arrays.asList(sportsTeam1, sportsTeam2, sportsTeam3, sportsTeam4));

        Phrase greeting1 = new Phrase("Hello", "Greetings");
        Category greetings = new Category("Greetings", Arrays.asList(greeting1));

        Phrase goodbye1 = new Phrase("Goodbye", "Goodbyes");
        Phrase goodbye2 = new Phrase("Adios", "Goodbyes");
        Phrase goodbye3 = new Phrase("Au revoir", "Goodbyes");
        Category goodbyes = new Category("Goodbyes", Arrays.asList(goodbye1, goodbye2, goodbye3));

        Phrase language1 = new Phrase("English", "Languages");
        Phrase language2 = new Phrase("Italian", "Languages");
        Phrase language3 = new Phrase("French", "Languages");
        Phrase language4 = new Phrase("German", "Languages");
        Category languages = new Category("Languages", Arrays.asList(language1, language2, language3, language4));

        List<Category> allCategories = Arrays.asList(sportsTeams, greetings, goodbyes, languages);
        int numberOfCategories = 2;
        int numberOfPhrasesPerCategory = 3;

        List<CategoryAndPhrase> categoriesAndPhrases = allCategories.stream()
                .filter(category -> category.getPhrases().size() >= numberOfPhrasesPerCategory) // remove the categories which don't have enough phrases to match our criteria
                .limit(numberOfCategories) // reduce the list to the number categories we require
                .map(Category::getPhrases) // change the stream so it is now a stream of the phrases for the selected categories
                .limit(numberOfPhrasesPerCategory) // reduce the phrases for each of the selected categories to the number of phrases we require
                .flatMap(List::stream)
                .map(phrase -> new CategoryAndPhrase(phrase.getCategory(), phrase.getName())) // create the new object for each of the selected phrases
                .collect(Collectors.toCollection(ArrayList::new));

        categoriesAndPhrases.forEach(categoryAndPhrase -> System.out.println(categoryAndPhrase));
    }

    class Category {

        private final String name;
        private final List<Phrase> phrases;

        public Category(final String name, final List<Phrase> phrases) {
            this.name = name;
            this.phrases = phrases;
        }

        public String toString() {
            return name;
        }

        public String getName() {
            return name;
        }

        public List<Phrase> getPhrases() {
            return phrases;
        }
    }

    class Phrase {

        private final String name;
        private final String category;

        public Phrase(final String name, final String category) {
            this.name = name;
            this.category = category;
        }

        public String toString() {
            return name;
        }

        public String getName() {
            return name;
        }

        public String getCategory() {
            return category;
        }
    }

    class CategoryAndPhrase {

        private final String category;
        private final String phrase;

        public CategoryAndPhrase(final String category, final String phrase) {
            this.category = category;
            this.phrase = phrase;
        }

        public String toString() {
            return "Category: [" + category + "], Phrase: [" + phrase + "]";
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-09-14 17:30:00

在看到给定数量的元素后,limit()停止处理流元素。

下面是您的代码的实际操作:

代码语言:javascript
复制
List<CategoryAndPhrase> categoriesAndPhrases = allCategories.stream()
        .filter(category -> category.getPhrases().size() >= numberOfPhrasesPerCategory) // remove the categories which don't have enough phrases to match our criteria
        .limit(numberOfCategories) // reduce the list to the number categories we require
        .map(Category::getPhrases) // transforms the Stream<Category> into a Stream<List<Phrase>>, where each category of the original stream is "replaced" by its list of phrases.
        .limit(numberOfPhrasesPerCategory) // only process N lists among all the lists of phrases

相反,你应该做的是:

代码语言:javascript
复制
List<CategoryAndPhrase> categoriesAndPhrases = allCategories.stream()
        .filter(category -> category.getPhrases().size() >= numberOfPhrasesPerCategory) // remove the categories which don't have enough phrases to match our criteria
        .limit(numberOfCategories) // reduce the list to the number categories we require
        .flatMap(category -> this.createCategoryAndPhrases(category, numberOfPhrasesPerCategory))
        .collect(Collectors.toList());

createCategoryAndPhrases方法应该如下所示:

代码语言:javascript
复制
private Stream<CategoryAndPhrase> createCategoryAndPhrases(Category category, int maxNumberOfPhrasesPerCategory) {
    return category.getPhrases().stream()
        .limit(maxNumberOfPhrasesPerCategory)
        .map(phrase -> new CategoryAndPhrase(category, phrase.getName()));
}
票数 4
EN

Stack Overflow用户

发布于 2017-09-14 17:28:08

在您的代码中,您基本上是对原始流应用了两次限制。取而代之的是这里

代码语言:javascript
复制
.flatMap(List::stream)

您应该返回调用limit的流:

代码语言:javascript
复制
.flatMap(d -> d.stream().limit(numberOfPhrasesPerCategory))
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46224931

复制
相关文章

相似问题

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