基于另一组的Java 8过滤器集

Kes*_*esh 5 java java-8

使用Java 8新结构(例如流),有没有办法Set根据另一个集合中的顺序过滤?

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");
Run Code Online (Sandbox Code Playgroud)

我希望根据集合过滤来自集合persons的项目names,这样只有那些指定了其名称的人才names会被保留,但是按照它们出现的顺序names.

所以,我想要

Set<Person> filteredPersons = ...;
Run Code Online (Sandbox Code Playgroud)

第一个元素是Person("B", 27)第二个元素Person("A", 23).

如果我这样做,

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

names如果我没有记错的话,订单不能保证与in相同.

我知道如何使用简单的for循环来实现这一点; 我只是在寻找一种java 8方式.

谢谢你的期待!

编辑:

用于循环,达到相同的结果:

Set<Person> filteredPersons = new LinkedHashSet<>();
for (String name : names) {
  for (Person person : persons) {
    if (person.getName().equalsIgnoreCase(name)) {
      filteredPersons.add(person);
      break;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

LinkedHashSet实施确保秩序得以维持.

eri*_*son 6

final Set<Person> persons = ...
Set<Person> filteredPersons = names.stream()
    .flatMap(n -> 
        persons.stream().filter(p -> n.equals(p.getName()))
    )
    .collect(Collectors.toCollection(LinkedHashSet::new));
Run Code Online (Sandbox Code Playgroud)

收集通过每个名称过滤它们创建的人员流.这对于所提供的示例的情况来说很快,但是会随着人数线性地缩放,例如O(N*P).

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

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));
Run Code Online (Sandbox Code Playgroud)

  • 你能详细说明_why_这个代码解决了OP问题吗? (4认同)