【问题标题】:Fetch subset from a superset using Java Streams使用 Java Streams 从超集中获取子集
【发布时间】:2018-05-22 08:33:33
【问题描述】:

我需要从给定的超级列表中获取子列表,如下所述。

假设我有一个“Person”对象的超级列表,如下所示:

List<Person> personsList = new ArrayList<>();
personsList.add(new Person("John", 28));
personsList.add(new Person("Paul", 29));
personsList.add(new Person("Adam", 30));
personsList.add(new Person("Peter", 31));
personsList.add(new Person("Pat", 32));

让Person类定义如下:

class Person {
    public String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }
}

给定一个像这样的子列表:

String [] names = {"John", "Paul", "Adam"};
List<String> namesList = Arrays.asList(names);

我想获取名称为JohnPaulAdam 的人员对象。

我是 Java 流的新手,这是我迄今为止为满足我的要求所做的尝试。

List<Person> finalList = personsList.stream().filter(p -> namesList.contains(p.name))
                .collect(Collectors.toCollection(() -> new ArrayList<Person>()));

我得到了想要的结果,但我想知道是否有任何其他有效的方法来实现这一点(我主要认为 namesList.contains(p.name) 有点低效)。

如果有更好的方法,请告诉我。

【问题讨论】:

    标签: java list arraylist java-8 java-stream


    【解决方案1】:

    假设在数组中重复名称是没有意义的,最好的方法是在名称中的Set&lt;T&gt; 中找到名称。这很容易实现。将数组转换为 List 并在接受任何集合后立即将其包含在 HashSet&lt;T&gt; 的构造函数中。

    String [] names = {"John", "Paul", "Adam"};
    Set<String> set = new HashSet<>(Arrays.asList(names));
    

    现在使用与您尝试相同的 Stream-API。仅使用静态方法Collectors.toList()

    List<Person> list= personsList.stream()
        .filter(i -> set.contains(i.getName()))
        .collect(Collectors.toList());
    

    结果将仅包含 JohnPaulAdam 人员的对象。

    【讨论】:

    • 谢谢@Nikolas。所以,我使用“包含”的基本想法仍然很好,尽管那时我可以使用 Collectors.toList()。另外,我认为您的回答中说结果将仅包含“Peter”和“Pat”人员对象是一个错字?
    • 我已经编辑过了。这当然是我的错。 :) Stream::filter 返回一个 Stream,其中的元素与给定的 Predicate 匹配。
    【解决方案2】:

    nameList 定义为 Set 会更有效,但如果列表仅包含 3 个名称,则差异不会真正明显。

    所以是这样的:

    Set<String> namesList = new HashSet<> (Arrays.asList("John", "Paul", "Adam"));
    
    List<Person> finalList = personsList.stream()
                                        .filter(p -> namesList.contains(p.name))
                                        .collect(Collectors.toList());
    

    注意:我还将收集器更改为 toList,因为这显然是您需要的。

    【讨论】:

    • 谢谢@assylias。所以,虽然我本来可以使用 Collectors.toList(),但我使用“包含”的基本想法仍然很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 2015-03-05
    • 1970-01-01
    • 2015-11-12
    • 1970-01-01
    • 2015-06-19
    相关资源
    最近更新 更多