根据一个属性对列表进行过滤。

时间:2020-11-28 20:44:42

I have a class called Person -

我有一门课叫Person -

public class Person implements Nameable {
    private String name;

    public String getName(){
        return name;
    }
}

Now I have two lists -

现在我有两个列表

List<Person>  persons = // some persons
List<Person> subsetOfPersons = // some duplicate persons, but different objects and don't share the same identity

Now I would like to filter the persons which are not present in the subsetOfPersons, equality criteria is name property and Person doesn't have equals.

现在我想要过滤掉subsetOfPersons中没有的人,平等标准是name property而Person则没有equal。

How can I do this?

我该怎么做呢?

2 个解决方案

#1


9  

I'm sure there's a simpler way... the below would transform person to name for the sake of comparison. For the subsetOfPersons, we actually create a list of names directly, since that's all we really need from them. For the persons, we keep the transformation limited to the context of the comparison.

我相信有更简单的方法……下面是为了比较而变换人名。对于subsetOfPersons,我们实际上直接创建了一个名称列表,因为这是我们真正需要的。对于个人而言,我们将转型局限于比较的语境。

    Iterable<Person> filtered = Iterables
            .filter(
                persons, 
                Predicates.not(
                    Predicates.compose(
                        Predicates.in(ImmutableSet.copyOf(Iterables.transform(subsetOfPersons, personToNamefunction))),
                        personToNamefunction
                    )
                )
            );

Edit: Thought you might appreciate a JUnit:

编辑:你可能会欣赏JUnit:

package com.*.test;

import static org.junit.Assert.*;

import java.util.Iterator;

import org.junit.Test;

import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;

public class PersonTest {
    public class Person {
        private String name;

        public String getName(){
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    @Test
    public void testNameBasedFiltering() {
        Person bob = createPerson("bob");
        Person jim = createPerson("jim");
        Person pam = createPerson("pam");
        Person roy = createPerson("roy");

        ImmutableList<Person> persons = ImmutableList.of(
                bob,
                jim,
                pam,
                roy); 
        ImmutableList<Person> subsetOfPersons = ImmutableList.of(
                createPerson("jim"),
                createPerson("pam"));

        Function<Person, String> personToNamefunction = new Function<Person, String>() {
            public String apply(Person arg0) {
                return arg0.getName();
            }
        };

        Iterable<Person> filtered = Iterables
                .filter(
                    persons, 
                    Predicates.not(
                        Predicates.compose(
                            Predicates.in(ImmutableSet.copyOf(Iterables.transform(subsetOfPersons, personToNamefunction))),
                            personToNamefunction
                        )
                    )
                );

        for (Person person : filtered) {
            assertNotSame(jim, person);
            assertNotSame(pam, person);         
        }
    }

    public Person createPerson(String name) {
        Person person = new Person();
        person.setName(name);

        return person;
    }

}

Edit again: Missed the "not" requirement the first time. Easy fix--with predicates, you can just wrap with Predicates.not(..)!

再次编辑:第一次错过了“not”要求。简单修复——使用谓词,您可以使用谓词进行包装。

#2


0  

Seems like you will have to manually iterate over both Lists (sounds lame, but that's the only thing I could think).

似乎您将不得不手工遍历两个列表(听起来很糟糕,但这是我唯一能想到的事情)。

outer loop: persons
   inner loop: subsetOfPersons
       compare person and sub person names and create another list with intersection of the      two

#1


9  

I'm sure there's a simpler way... the below would transform person to name for the sake of comparison. For the subsetOfPersons, we actually create a list of names directly, since that's all we really need from them. For the persons, we keep the transformation limited to the context of the comparison.

我相信有更简单的方法……下面是为了比较而变换人名。对于subsetOfPersons,我们实际上直接创建了一个名称列表,因为这是我们真正需要的。对于个人而言,我们将转型局限于比较的语境。

    Iterable<Person> filtered = Iterables
            .filter(
                persons, 
                Predicates.not(
                    Predicates.compose(
                        Predicates.in(ImmutableSet.copyOf(Iterables.transform(subsetOfPersons, personToNamefunction))),
                        personToNamefunction
                    )
                )
            );

Edit: Thought you might appreciate a JUnit:

编辑:你可能会欣赏JUnit:

package com.*.test;

import static org.junit.Assert.*;

import java.util.Iterator;

import org.junit.Test;

import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;

public class PersonTest {
    public class Person {
        private String name;

        public String getName(){
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    @Test
    public void testNameBasedFiltering() {
        Person bob = createPerson("bob");
        Person jim = createPerson("jim");
        Person pam = createPerson("pam");
        Person roy = createPerson("roy");

        ImmutableList<Person> persons = ImmutableList.of(
                bob,
                jim,
                pam,
                roy); 
        ImmutableList<Person> subsetOfPersons = ImmutableList.of(
                createPerson("jim"),
                createPerson("pam"));

        Function<Person, String> personToNamefunction = new Function<Person, String>() {
            public String apply(Person arg0) {
                return arg0.getName();
            }
        };

        Iterable<Person> filtered = Iterables
                .filter(
                    persons, 
                    Predicates.not(
                        Predicates.compose(
                            Predicates.in(ImmutableSet.copyOf(Iterables.transform(subsetOfPersons, personToNamefunction))),
                            personToNamefunction
                        )
                    )
                );

        for (Person person : filtered) {
            assertNotSame(jim, person);
            assertNotSame(pam, person);         
        }
    }

    public Person createPerson(String name) {
        Person person = new Person();
        person.setName(name);

        return person;
    }

}

Edit again: Missed the "not" requirement the first time. Easy fix--with predicates, you can just wrap with Predicates.not(..)!

再次编辑:第一次错过了“not”要求。简单修复——使用谓词,您可以使用谓词进行包装。

#2


0  

Seems like you will have to manually iterate over both Lists (sounds lame, but that's the only thing I could think).

似乎您将不得不手工遍历两个列表(听起来很糟糕,但这是我唯一能想到的事情)。

outer loop: persons
   inner loop: subsetOfPersons
       compare person and sub person names and create another list with intersection of the      two