基于另一个集合的Java 8筛选器集合

基于另一个集合的Java 8筛选器集合,java,java-8,Java,Java 8,使用Java8新构造,例如streams,是否有方法根据另一个集合中的顺序过滤集合 Set<Person> persons = new HashSet<>(); persons.add(new Person("A", 23)); persons.add(new Person("B", 27)); persons.add(new Person("C", 20)); List<String> names = new ArrayList<>(); n

使用Java8新构造,例如streams,是否有方法根据另一个集合中的顺序过滤
集合

Set<Person> persons = new HashSet<>();

persons.add(new Person("A", 23));
persons.add(new Person("B", 27));
persons.add(new Person("C", 20));

List<String> names = new ArrayList<>();
names.add("B");
names.add("A");
其中第一个元素是
人(“B”,27)
,第二个元素是
人(“A”,23)

如果我做下面的事情

Set<Person> filteredPersons = new HashSet<>(persons);
filteredPersons = filteredPersons.stream().filter(p -> names.contains(p.getName())).collect(Collectors.toSet());

LinkedHashSet
实现可确保维护订单。

您可以使用以下类似的方法(未经测试):

并且,如上所述,收集到
列表中,而不是
集合中


正如Alexis在评论中提到的,你也可以写得更简洁:

.sorted(comparingInt(p -> names.indexOf(p.getName())))
其中,
comparingit
来自
比较器的
静态导入

最终设置人员=。。。
final Set<Person> persons = ...
Set<Person> filteredPersons = names.stream()
    .flatMap(n -> 
        persons.stream().filter(p -> n.equals(p.getName()))
    )
    .collect(Collectors.toCollection(LinkedHashSet::new));
Set filteredPersons=names.stream() .flatMap(n-> persons.stream().filter(p->n.equals(p.getName())) ) .collect(Collectors.toCollection(LinkedHashSet::new));
收集通过按姓名筛选创建的人员流。对于所提供的示例这样的情况,这是很快的,但会随着人数的增加而线性增加,如O(N*P)

对于较大的人员和姓名集合,创建可用于按姓名查找人员的索引总体上会更快,按O(N+p)缩放:

Map index=persons.stream()
.collect(Collectors.toMap(Person::getName,Function.identity());
Set filteredPersons=names.stream()
.map(索引::get)
.filter(对象::非空)
.collect(Collectors.toCollection(LinkedHashSet::new));
我愿意更改set实现,例如更改为 LinkedHashSet如上述示例所示,以实现最终目标

如果你完全改变了用来存储<代码>人>代码>的数据结构,那么你可能应该考虑使用<代码> map < /C> >,因为这会大大提高算法的效率。

Map<String, Person> persons = new HashMap<>();

persons.put("A", new Person("A", 23));
persons.put("B", new Person("B", 27));
persons.put("C", new Person("C", 20));

List<String> names = new ArrayList<>();
names.add("B");
names.add("A");

List<Person> filteredPersons = names.stream()
        .map(persons::get)
        .filter(Objects::nonNull)
        .collect(Collectors.toList());
Map persons=newhashmap();
人。将(“A”,新的人(“A”,23));
(B)新的人(B),27);
(C)新的人(C),20);
列表名称=新的ArrayList();
名称。添加(“B”);
名称。添加(“A”);
List filteredPersons=names.stream()
.map(persons::get)
.filter(对象::非空)
.collect(Collectors.toList());

如果字母大小写在
个人
姓名
中可能不同,您可以执行
。在
映射
的键中,toLowerCase()
通常是无序的,因此您不能期望结果集具有特定的顺序。如果您收集到一个列表,这是可能的。您确定不想使用
SortedSet
而不是
Set
?可以有两个以上的人同名吗?HashSet没有定义的顺序,因此尝试保留顺序并不意味着任何事情。@Tunaki列表不会包含重复的名称。PeterLawrey,Matthew I愿意更改集合实现,例如,更改为上面示例中所示的LinkedHashSet,以实现最终目标。您可以使用(静态导入)
.sorted(comparingit(p->names.indexOf(p.getName())避免一点比较器的样板文件)
你能详细解释一下为什么这个代码解决了OPs问题吗?这确实解决了我的问题。与使用上面给出的映射的其他解决方案相比,我只是有点不确定它的效率。如果我理解正确,将对每个n执行
persons
筛选操作,类似于嵌套for循环?@HP是的,您是对的。我添加了另一种使用地图的大型收集方法,但比Helder Pereira的解决方案更有效。他的方法执行两次哈希查找,这比一次查找后进行空测试要慢。如果姓名的数量小于某个限制,第一种解决方案仍将比构建地图快。如果
姓名
包含的人名不出现在
人名
中,则可能会出现问题,如
“D”
。在这种情况下,我们最终会得到
null
,之后可能会得到NPEflatMap
filter
组合没有这个问题。我认为OP没有提到这一点,但很容易解决:在
之前添加
.filter(persons::containsKey)
,或者在
之后添加
.filter(Objects::nonNull)
。True,OP没有提到这一点,但他也没有否定这一点,这就是为什么值得一提的原因(为了安全起见,你可以在你的评论中添加解决方案);那是浪费资源。所以我更喜欢
.map(persons::get).filter(Objects::nonNull)
.sorted(comparingInt(p -> names.indexOf(p.getName())))
final Set<Person> persons = ...
Set<Person> filteredPersons = names.stream()
    .flatMap(n -> 
        persons.stream().filter(p -> n.equals(p.getName()))
    )
    .collect(Collectors.toCollection(LinkedHashSet::new));
Map<String, Person> index = persons.stream()
    .collect(Collectors.toMap(Person::getName, Function.identity()));
Set<Person> filteredPersons = names.stream()
    .map(index::get)
    .filter(Objects::nonNull)
    .collect(Collectors.toCollection(LinkedHashSet::new));
Map<String, Person> persons = new HashMap<>();

persons.put("A", new Person("A", 23));
persons.put("B", new Person("B", 27));
persons.put("C", new Person("C", 20));

List<String> names = new ArrayList<>();
names.add("B");
names.add("A");

List<Person> filteredPersons = names.stream()
        .map(persons::get)
        .filter(Objects::nonNull)
        .collect(Collectors.toList());