1

我在 Java 中有一个包含人的集合:

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

我也有一大堆人的名单(其中有些人拥有相同的名字,例如,世界上不止一个“鲍勃”)。

List<Person> theWorld = // ... a BIG list of people

我想遍历这个列表并将一个人添加到uniquePeople集合中,当且仅当他们的名字不存在于集合中时,例如:

for (Person person : theWorld) {
    uniquePeople.add(person IFF uniquePeople.doesNotContain(person.name));
}

有没有一种简单的方法可以在 Java 中做到这一点?此外,番石榴可能会这样做(?)但我根本没有使用过它,所以我会很感激在正确的方向上的一点。

4

4 回答 4

4

更好的选择是放弃使用 Set 而是使用 a Map<String, Person>(键控名称)。

如果你想使用一个集合,我建议你使用一个新的对象类型(它只包含一个名称,可能还有一个对 Person 的引用)。

确保您覆盖 equals 以便它只会比较名称,然后您可以获得一组所有唯一的人。

您还可以将 person 子类化以覆盖 equals 以执行您想要的操作。

根据定义,集合不会只对一个人执行您想要的操作,因为它们完全依赖于使用 equals,因此这些是您的解决方法选项。您还可以实现(或在线查找)一个使用比较器而不是依赖于 equals 的集合,但我认为标准 java 中不存在这样的类。

于 2013-04-18T20:33:14.743 回答
3

Equivalence如果您不想(或不能)覆盖 equals 和 hashCode,请使用 Guava包装您的对象:

Set<Equivalence.Wrapper<Person>> set = Sets.newHashSet();
Equivalence<Person> personEquivalence = Equivalence.onResultOf(
    new Function<Person, String>() {
      @Override public String apply(Person p) {
        return p.name;
      }
    });
set.add(personEquivalence.wrap(new Person("Joe", "Doe")));
set.add(personEquivalence.wrap(new Person("Joe", "Doe")));
set.add(personEquivalence.wrap(new Person("Jane", "Doe")));
System.out.println(set);
// [PersonEquivalence@8813f2.wrap(Person{firstName=Jane, lastName=Doe}),
//  PersonEquivalence@8813f2.wrap(Person{firstName=Joe, lastName=Doe})]

@DanielWilliams 也有一个好主意,但使用Equivalence.Wrapper更多的是自我记录 - 毕竟你不想创建包装器以外的新对象。

于 2013-04-18T20:38:56.853 回答
2

我不确定为什么人们在这里被否决。

你绝对想要一套。您的要求不仅满足“集合”的定义和功能,而且集合实现旨在通过散列或比较身份快速识别重复项。

假设您有一个 List 实现,它带有一个委托和一个谓词:

List uniquePeople = new PredicatedList(new ArrayList(),UnqiuePersonPredicate.getInstance())

public class PredicatedList<T> implements List<T> {

    private List<T> delegate = null;
    private Predicate<T> predicate;

    public PredicatedList<List<T> delegate, Predicate p) {
     this.delegate = delegate;
     this.predicate = p;
    }
   // implement list methods here and apply 'p' before calling your insertion functions

   public boolean add(Person p) {
     if(predicate.apply(p))
        delegate.add(p);

   }
}

为此,您需要有一个谓词来遍历列表以找到相等的元素。这是一个 O(N) 操作。如果你使用 HashSet,那么它是 O(1) < n < O(N)。您的摊销身份检查是负载因子 * N。而且,通常更接近 O(1)

如果您使用 TreeSet,您将得到 O(log(n)),因为元素按身份排序,并且您只需要 log(n) 时间进行二分搜索。

根据“名称”或您想要的任何内容定义 hashCode()/equals 并使用 HashSet 或使用 TreeSet 并定义 Comparable/Comparator

如果您的返回类型必须是列表,则执行以下操作: Set uniquePeople = new HashSet(); uniquePeople.add(...);

列出人员 = new LinkedList(uniquePeople);

于 2013-04-18T20:47:27.973 回答
1

你可以用番石榴来做,唯一的事情是 Person 需要一个 equals/hashcode 方法。

ImmutableSet<String> smallList = ImmutableSet.of("Eugene","Bob");
ImmutableSet<String> bigList   = ImmutableSet.of("Eugene","Bob","Alex","Bob","Alex");

System.out.println(Iterables.concat(smallList, Sets.difference(bigList, smallList)));

//output is going to be : [Eugene, Bob, Alex]
于 2013-04-18T20:38:53.870 回答