Подтвердить что ты не робот

Фильтрация по списку на основе одного свойства с guava

У меня есть класс Person -

public class Person implements Nameable {
    private String name;

    public String getName(){
        return name;
    }
}

Теперь у меня есть два списка -

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

Теперь я хотел бы отфильтровать persons, которых нет в subsetOfPersons, критерием равенства является свойство name, а Person не имеет равных.

Как я могу это сделать?

4b9b3361

Ответ 1

Я уверен, что есть более простой способ... ниже будет трансформировать человека, чтобы назвать его ради сравнения. Для subsetOfPersons мы фактически создаем список имен напрямую, так как все, что нам действительно нужно от них. Для persons мы ограничиваем трансформацию контекстом сравнения.

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

Изменить: подумал, что вы можете оценить JUnit:

package com.stackoverflow.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;
    }

}

Изменить снова. В первый раз пропустили требование "нет". Простое исправление - с предикатами вы можете просто обернуть Predicates.not(..)!

Ответ 2

Похоже, вам придется вручную перебирать оба списка (звуки хромые, но это единственное, что я мог подумать).

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