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

より良いオプションは、セットの使用を放棄し、代わりにMap<String, Person>(名前のキーオフ) を使用することです。

セットを使用する場合は、新しいオブジェクト タイプを使用することをお勧めします (これには、名前と、場合によっては Person への参照のみが含まれます)。

equals をオーバーライドして、名前のみを比較し、すべての一意の人物のセットを取得できるようにしてください。

person をサブクラス化して equals をオーバーライドして、必要なことを行うこともできます。

定義上、set は equals の使用に完全に依存しているため、人だけで必要なことを行うことはできません。これらは回避策のオプションです。equals に依存する代わりにコンパレータを使用するセットを実装 (またはオンラインで検索) することもできますが、そのようなクラスは標準の Java には存在しないと思います。

于 2013-04-18T20:33:14.743 に答える
3

Equivalenceequals と 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 実装があるとしましょう:

リスト uniquePeople = 新しい PredicatedList(新しい 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) になります。償却された ID チェックは負荷係数 * N です。そして、通常は O(1) にかなり近くなります。

TreeSet を使用すると、O(log(n)) が得られます。これは、要素が ID でソートされ、バイナリ検索に log(n) 時間しか必要ないためです。

「名前」または必要なものに基づいて hashCode()/equals を定義し、HashSet を使用するか、TreeSet を使用して Comparable/Comparator を定義します。

戻り値の型がリストでなければならない場合は、次のようにします。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 に答える