セットから要素を取得する


323

Set別の要素と等しい要素を取得する操作を提供しないのはなぜですか?

Set<Foo> set = ...;
...
Foo foo = new Foo(1, 2, 3);
Foo bar = set.get(foo);   // get the Foo element from the Set that equals foo

Setと等しい要素が含まれているかどうかを確認できますが、barなぜその要素を取得できないのですか?:(

明確にするために、equalsメソッドはオーバーライドされていますが、すべてではなく、フィールドの1つだけをチェックしています。したがって、Foo等しいと見なされる2つのオブジェクトは実際には異なる値を持つ可能性があるため、を使用することはできませんfoo


2
この投稿はすでに広く議論されており、良い答えが提案されています。ただし、順序付けされたセットを探しているだけの場合SortedSetは、マップベースのとその実装を使用するだけです(たとえばTreeSet、へのアクセスが可能first())。
Eliran Malka 14

3
上記とまったく同じケースで、この方法も見逃しています。Objective-C(NSSet)にはこのようなメソッドがあります。これは呼び出されmembermemberメソッド内のパラメータと「等しい」を比較するセット内のオブジェクトを返します(もちろん、オブジェクトは異なり、プロパティも異なるため、等しいかどうかはチェックできません)。
メッキー2015年

回答:


118

要素が等しい場合、要素を取得しても意味がありません。A Mapはこの使用例に適しています。


それでも要素を見つけたい場合は、イテレータを使用するしかありません:

public static void main(String[] args) {

    Set<Foo> set = new HashSet<Foo>();
    set.add(new Foo("Hello"));

    for (Iterator<Foo> it = set.iterator(); it.hasNext(); ) {
        Foo f = it.next();
        if (f.equals(new Foo("Hello")))
            System.out.println("foo found");
    }
}

static class Foo {
    String string;
    Foo(String string) {
        this.string = string;
    }
    @Override
    public int hashCode() { 
        return string.hashCode(); 
    }
    @Override
    public boolean equals(Object obj) {
        return string.equals(((Foo) obj).string);
    }
}

234
要素を取得することには絶対にポイントがあるかもしれません。要素がすでにセットに追加された後で、要素の値の一部を更新したい場合はどうなりますか?たとえば、OPが指定したように、.equals()がすべてのフィールドを使用しない場合。より効率の悪い解決策は、要素を削除して、その値を更新して再度追加することです。
KyleM 2013

14
私はまだと主張Map適しています(Map<Foo, Foo>この場合は。)
dacwe

22
@dacwe、正確にそれを回避する方法を探し始めたので、私はここに着きました!キーと対応する値の両方として同時に動作するオブジェクトは、まさにセットのすべてのことです。私の場合、キー(文字列)のセットから複雑なオブジェクトを取得します。この文字列は、マッピングされるオブジェクトにカプセル化されています(一意です)。実際には、オブジェクト全体がこのキーを中心に「回転」します。さらに、呼び出し元は上記の文字列を知っていますが、オブジェクト自体は知っていません。それがキーで取得したい理由です。もちろん今はMapを使用していますが、それは奇妙な動作のままです。
pauluss86 2014年

4
@KyleM私はユースケースを理解していますが、hashCode / equalsの一部である属性に触れないことの重要性を強調したいと思います。Set Javadocから:「注:変更可能なオブジェクトをセット要素として使用する場合は、細心の注意を払う必要があります。オブジェクトの値が、オブジェクトがセット内の要素。」-これらのオブジェクトは不変であるか、少なくとも不変のキー属性を持つことをお勧めします。
stivlo 2015

5
私はあなたがMap<Foo, Foo>代替として使用できることに同意します。欠点は、マップは常に少なくともキーと値を保存する必要がある(そしてパフォーマンスのためにハッシュも保存する必要がある)一方で、セットは値を保存するだけで済む(そして多分パフォーマンスのためにハッシュします)。したがって、優れたセット実装は同等に高速ですがMap<Foo, Foo>、メモリを最大50%節約できます。Javaの場合、HashSetは内部的にはHashMapに基づいているため、問題にはなりません。
メッキー2015年

372

正確な質問「なぜSet別の要素と等しい要素を取得する操作を提供しないのですか?」に答えるには、答えは次のとおりです。コレクションフレームワークの設計者はあまり前向きではなかったからです。彼らはあなたの非常に正当なユースケースを予想していなかったので、単純に「数学セットの抽象化をモデル化」しようとし(javadocから)、有用なget()メソッドを追加するのを忘れていました。

暗黙の質問である「どのようにして要素を取得するのについてです。最善の解決策は、のMap<E,E>代わりにを使用してSet<E>、要素をそれ自体にマップすることです。このようにして、「セット」から要素を効率的に取得できます。これは、のget()メソッドがMap効率的なハッシュテーブルまたはツリーアルゴリズムを使用して要素を見つけるためです。必要に応じSetて、追加のget()メソッドを提供する独自の実装を記述して、をカプセル化できますMap

次の答えは私の意見では悪いか間違っています:

「すでに同等のオブジェクトを持っているので、要素を取得する必要はありません」:質問ですでに示したように、アサーションは間違っています。等しい2つのオブジェクトは、オブジェクトの等価性に関係のない異なる状態を持つ可能性があります。目標はSet、「クエリ」として使用されるオブジェクトの状態ではなく、に含まれる要素のこの状態にアクセスすることです。

「イテレータを使用する以外に選択肢はありません」:これは、大規模なセットに対して完全に非効率なコレクションに対する線形検索です(皮肉なことに、内部的にSetは、効率的にクエリできるハッシュマップまたはツリーとして編成されています)。やめろ!そのアプローチを使用することにより、実際のシステムで深刻なパフォーマンスの問題が発生しました。私の考えでは、不足しているget()メソッドについてひどいのは、それを回避するのが少し面倒なほどではありませんが、ほとんどのプログラマーは影響を考慮せずに線形検索アプローチを使用します。


27
ええ。equalsの実装をオーバーライドして、等しくないオブジェクトが「等しい」ようにすることは、ここでの問題です。「このオブジェクトと同じオブジェクトを取得して」と言ってから、同じでないオブジェクトが返されることを期待するメソッドを要求すると、気が狂ってメンテナンスの問題が発生しやすくなります。他の人が示唆しているように、マップを使用すると、これらの問題がすべて解決されます。等しくない2つのオブジェクトがマップ内で同じキーを持つ可能性があり、同じキーを持つことでそれらの間の関係がわかることは簡単に理解できます。
David Ogren、2014

20
強い言葉、@ David Ogren。え?クレイジー?ただし、コメントでは、「同一」と「等しい」という言葉を同じ意味で使用しているように使用しています。彼らはしない。具体的には、Javaでは、IDは「==」演算子で表され、等価性はequals()メソッドで表されます。同じことを意味するのであれば、equals()メソッドはまったく必要ありません。他の言語では、これはもちろん異なる場合があります。たとえば、Groovyでは、IDはis()メソッドであり、等価性は「==」です。おかしいですね。
jschreiner 2014

15
私が同等の単語を使用すべきだったときに同じ単語を使用したというあなたの批判は非常に有効です。しかし、FooとBarが「等しい」が、それらを同等に使用するには「十分に等しくない」ようにオブジェクトにequalsを定義すると、機能性と可読性/保守性の両方であらゆる種類の問題が発生します。Setのこの問題は、潜在的な問題の氷山の一角にすぎません。たとえば、等しいオブジェクトには同じハッシュコードが必要です。そのため、彼はハッシュの衝突の可能性があります。特にfoo以外のものを取得するために.get(foo)を呼び出すオブジェクトに夢中ですか?
David Ogren 14

12
たとえば、HashSetがHashMapのラッパーとして実装されている(キーをダミー値にマップする)ことはおそらく注目に値します。そのため、HashSetの代わりにHashMapを明示的に使用しても、メモリ使用にオーバーヘッドは発生しません。
Alexey B.

4
@ user686249私はこれが単なる学術的な議論に発展したように感じます。等しいものをオーバーライドすることに反対するのはやりすぎだったかもしれないと認めます。特にあなたのような用途で。しかし、私はまだこのメソッドを呼び出すという考えに反対していget()ます。あなたの例では、customerSet.get(thisCustomer)に混乱してしまいます。(一方、マップは、多くの回答で提案されているように)canonicalCustomerMap.get(this customer)で問題ありません。NSSet上のObjective-Cのメンバーメソッドなど、より明確に名前が付けられたメソッドでもかまいません。
David Ogren、2015

19

同等のオブジェクトがある場合、セットのオブジェクトが必要なのはなぜですか?キーによってのみ「等しい」場合は、Mapを選択することをお勧めします。

とにかく、以下はそれを行います:

Foo getEqual(Foo sample, Set<Foo> all) {
  for (Foo one : all) {
    if (one.equals(sample)) {
      return one;
    }
  } 
  return null;
}

Java 8では、これはワンライナーになる可能性があります。

return all.stream().filter(sample::equals).findAny().orElse(null);

私はこの答えが好きです。2つのreturnステートメントを使用することは避けます。
レオ

8
@Leoおかげで、しかし、単一の出口のパラダイムがOOPに反しないとFortranやCOBOLよりも近代的な言語のための大部分は無効であるが、また見softwareengineering.stackexchange.com/questions/118703/...
アルネBurmeister

1
Setの代わりにMapを使用することは、より良いオプションのように見えます。Setの要素を反復することは、Mapから単一の値を取得するよりも多くの作業です。(O(N)対O(1))
ジェイミーフルノイ2018年

@JamieFlournoyそうです、同じ要素を異なる要素について複数回チェックする必要がある場合は、はるかに優れています。最初にマップを作成するのに多くの労力が必要になるため、1回の使用ではありません。
Arne Burmeister、2018年

18

セットをリストに変換しget、リストのメソッドを使用する

Set<Foo> set = ...;
List<Foo> list = new ArrayList<Foo>(set);
Foo obj = list.get(0);

37
わかりません。これにより、セットの任意のオブジェクトが取得されます。オブジェクトでありません。
aioobe 2017

14

Javaのデフォルトセットは、jschreinerが正確に説明しているように、残念ながら「取得」操作を提供するようには設計されていません。

(によって提案された関心の要素を見つけるためにイテレータを使用してのソリューションdacweを)または要素を削除し、その値を更新(によって提案とそれを再度追加するKyleMは)、仕事ができるが、非常に非効率的であることができます。

等しいの実装をオーバーライドして、等しくないオブジェクトが「等しい」ようにすると、David Ogrenが正しく述べているように、メンテナンスの問題が発生しやすくなります。

そして、(多くの人が示唆しているように)Mapを明示的な置換として使用すると、imhoはコードのエレガントさを低下させます。

セットに含まれる要素の元のインスタンスにアクセスすることが目的である場合(私があなたのユースケースを正しく理解していることを願っています)、別の解決策を次に示します。


私は個人的に、Javaを使用したクライアントサーバービデオゲームの開発中に同じニーズを抱えていました。私の場合、各クライアントにはサーバーに格納されたコンポーネントのコピーがあり、問題はクライアントがサーバーのオブジェクトを変更する必要があるときでした。

インターネットを介してオブジェクトを渡すことは、クライアントがそのオブジェクトの異なるインスタンスをとにかく持つことを意味しました。この「コピーされた」インスタンスを元のインスタンスと一致させるために、Java UUIDを使用することにしました。

そこで、サブクラスの各インスタンスにランダムな一意のIDを自動的に与える抽象クラスUniqueItemを作成しました。

このUUIDはクライアントとサーバーインスタンス間で共有されるため、このようにマップを使用するだけで簡単に一致させることができます。

ただし、類似のユースケースで直接Mapを使用することは、依然として洗練されていませんでした。誰かが、マップの使用は管理と処理がより複雑になるかもしれないと主張するかもしれません。

これらの理由から、MagicSetと呼ばれるライブラリを実装しました。これにより、マップの使用が開発者に対して「透過」になります。

https://github.com/ricpacca/magicset


元のJava HashSetと同様に、MagicHashSet(ライブラリで提供されるMagicSetの実装の1つ)はバッキングHashMapを使用しますが、要素をキーとして使用し、ダミーの値を値として使用する代わりに、要素のUUIDをキーとして使用します値としての要素自体。これにより、通常のHashSetと比較して、メモリ使用量にオーバーヘッドが発生しません。

さらに、MagicSetはSetとまったく同じように使用できますが、getFromId()、popFromId()、removeFromId()などの追加機能を提供するいくつかのメソッドがあります。

それを使用する唯一の要件は、MagicSetに格納するすべての要素が、抽象クラスUniqueItemを拡張する必要があることです。


次のコード例は、同じUUID(またはそのUUIDのみ)を持つ都市の別のインスタンスを指定して、MagicSetから都市の元のインスタンスを取得することを想定しています。

class City extends UniqueItem {

    // Somewhere in this class

    public void doSomething() {
        // Whatever
    }
}

public class GameMap {
    private MagicSet<City> cities;

    public GameMap(Collection<City> cities) {
        cities = new MagicHashSet<>(cities);
    }

    /*
     * cityId is the UUID of the city you want to retrieve.
     * If you have a copied instance of that city, you can simply 
     * call copiedCity.getId() and pass the return value to this method.
     */
    public void doSomethingInCity(UUID cityId) {
        City city = cities.getFromId(cityId);
        city.doSomething();
    }

    // Other methods can be called on a MagicSet too
}

11

セットが実際にNavigableSet<Foo>(などTreeSet)およびFoo implements Comparable<Foo>である場合、使用できます

Foo bar = set.floor(foo); // or .ceiling
if (foo.equals(bar)) {
    // use bar…
}

(ヒントのための@ eliran-malkaのコメントに感謝します。)


5
私が完全に狂ってしまったという最初の考えを持って私のコードを読んでいる人を気にしないなら、これは素晴らしい解決策でしょう。
アダム

10

Java 8でできること:

Foo foo = set.stream().filter(item->item.equals(theItemYouAreLookingFor)).findFirst().get();

ただし、.get()がNoSuchElementExceptionをスローするか、またはオプション項目を操作できることに注意してください。


5
item->item.equals(theItemYouAreLookingFor)短縮できますtheItemYouAreLookingFor::equals
Henno Vermeulen

5
Object objectToGet = ...
Map<Object, Object> map = new HashMap<Object, Object>(set.size());
for (Object o : set) {
    map.put(o, o);
}
Object objectFromSet = map.get(objectToGet);

すべての要素をループするため、1つのgetのみを実行すると、これはあまり効果的ではありませんが、大きなセットで複数の取得を実行すると、違いがわかります。


5

なぜ:

Setは比較の手段を提供するのに有用な役割を果たすようです。重複する要素を格納しないように設計されています。

この意図/設計のため、格納されたオブジェクトへの参照をget()して変更すると、Setの設計意図が妨げられ、予期しない動作が発生する可能性があります。

JavaDocsから

変更可能なオブジェクトをセット要素として使用する場合は、十分な注意が必要です。オブジェクトがセット内の要素であるときに、等しい比較に影響を与えるようにオブジェクトの値が変更された場合、セットの動作は指定されません。

どうやって:

ストリームが導入されたので、次のことができます

mySet.stream()
.filter(object -> object.property.equals(myProperty))
.findFirst().get();

2

Arraysクラスの使用についてはどうですか?

import java.util.Arrays;
import java.util.List;
import java.util.HashSet;
import java.util.Arrays;

public class MyClass {
    public static void main(String args[]) {
        Set mySet = new HashSet();
        mySet.add("one");
        mySet.add("two");
        List list = Arrays.asList(mySet.toArray());
        Object o0 = list.get(0);
        Object o1 = list.get(1);
        System.out.println("items " + o0+","+o1);
    }
}

出力:
アイテム1、2



1

私は知っています、これはずっと前に尋ねられて答えられましたが、誰かが興味を持っているなら、ここに私の解決策があります-HashMapによってサポートされたカスタムセットクラス:

http://pastebin.com/Qv6S91n9

他のすべてのSetメソッドを簡単に実装できます。


7
単に1つにリンクするのではなく、例を含めることをお勧めします。
すべての労働者は必須です

1

そこに行ったことがある!Guavaを使用している場合、それをマップに変換する簡単な方法は次のとおりです。

Map<Integer,Foo> map = Maps.uniqueIndex(fooSet, Foo::getKey);

1

Iteratorクラスを使用できます

import java.util.Iterator;
import java.util.HashSet;

public class MyClass {
 public static void main(String[ ] args) {
 HashSet<String> animals = new HashSet<String>();
animals.add("fox");
animals.add("cat");
animals.add("dog");
animals.add("rabbit");

Iterator<String> it = animals.iterator();
while(it.hasNext()) {
  String value = it.next();
  System.out.println(value);   
 }
 }
}

1

HashSetからn番目の要素が必要な場合は、以下のソリューションを使用できます。ここでは、HashSetにModelClassのオブジェクトを追加しています。

ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
    m1 = (ModelClass) itr.next();
    if(nth == index) {
        System.out.println(m1);
        break;
    }
}

1

実装の最初の数行を見ると、次のjava.util.HashSetことがわかります。

public class HashSet<E>
    ....
    private transient HashMap<E,Object> map;

だから、HashSet用途はHashMapとにかく内部的に、どのあなただけ使用する場合ことを意味しHashMap、直接、キーと値あなたが欲しい効果を取得し、自分自身にいくつかのメモリを節約するのと同じ値を使用します。


1

使用する適切なオブジェクトはguavaのInternerのようです:

他の不変タイプのString.intern()と同等の動作を提供します。一般的な実装は、Interners クラスから利用できます。

また、concurrencyLevelや使用される参照のタイプなど、非常に興味深いレバーがいくつかあります(WeakInternerよりも便利であると思われるSoftInternerが提供されていないことに注意してください)。


0

Setの特定の実装はランダムアクセスである場合とそうでない場合があるためです

イテレータを取得し、Setをステップnext()実行できます。イテレータのメソッドを使用して、等しい要素が見つかったら必要な結果を返します。これは、実装に関係なく機能します。実装がランダムアクセスではない場合(リンクされたリストを使用したSetの画像)、get(E element)インターフェイスのメソッドは、コレクションを反復して返す要素を見つける必要があるため、不正であるget(E element)可能性があります。 Setが取得する要素に直接ジャンプできることが必要です。

contains() もちろん、実装に応じて、同じことをする必要がある場合とそうでない場合がありますが、名前は同じ種類の誤解を招くようには見えません。


2
get()メソッドが行うことはすべて、contains()メソッドによってすでに行われています。含まれているオブジェクトを取得してその.equals()メソッドを呼び出さないと、contains()を実装できません。API設計者は、一部の実装では低速になるものの、get()をjava.util.Listに追加することに抵抗がないように見えました。
ブライアンリンク2013年

これは本当だとは思いません。2つのオブジェクトは、等しいを介して等しい場合がありますが、==を介して同一ではありません。オブジェクトA、オブジェクトBを含むセットS、およびA.equals(B)がA!= Bであり、Bへの参照を取得したい場合、S.get(A)を呼び出して参照を取得できます。 B、Listのgetメソッドのセマンティクスを持つgetメソッドがあると仮定します。これは、S.contains(A)(そうするかどうか)をチェックするのとは異なる使用例です。これは、コレクションのユースケースでさえまれではありません。
Tom Tresansky、2013年

0

はい、HashMap...を使用しますが、特殊な方法で使用します。私HashMapがを疑似として使用しようとすると予想されるトラップSetは、の「実際の」要素Map/Setと「候補」要素、つまり、equal要素はすでに存在しています。これは決して簡単なことではありませんが、罠からあなたをそっと離します。

class SelfMappingHashMap<V> extends HashMap<V, V>{
    @Override
    public String toString(){
        // otherwise you get lots of "... object1=object1, object2=object2..." stuff
        return keySet().toString();
    }

    @Override
    public V get( Object key ){
        throw new UnsupportedOperationException( "use tryToGetRealFromCandidate()");
    }

    @Override
    public V put( V key, V value ){
       // thorny issue here: if you were indavertently to `put`
       // a "candidate instance" with the element already in the `Map/Set`: 
       // these will obviously be considered equivalent 
       assert key.equals( value );
       return super.put( key, value );
    }

    public V tryToGetRealFromCandidate( V key ){
        return super.get(key);
    }
}

次にこれを行います:

SelfMappingHashMap<SomeClass> selfMap = new SelfMappingHashMap<SomeClass>();
...
SomeClass candidate = new SomeClass();
if( selfMap.contains( candidate ) ){
    SomeClass realThing = selfMap.tryToGetRealFromCandidate( candidate );
    ...
    realThing.useInSomeWay()...
}

しかし...あなたが今したいcandidateプログラマが実際にすぐにそれを置く場合を除き、いくつかの方法で、自己破壊にMap/Set...あなたがしたいと思うcontains「汚染」にcandidateそれが結合していない限り、それのいずれかの使用がそうというMapこと「忌み嫌わます」おそらくSomeClass、新しいTaintableインターフェースを実装させることができます。

より満足のいく解決策は、以下のGettableSetです。ただし、これが機能するSomeClassためには、すべてのコンストラクターを非表示にする(または...ラッパークラスを設計して使用することができる)ために、の設計を担当する必要があります。

public interface NoVisibleConstructor {
    // again, this is a "nudge" technique, in the sense that there is no known method of 
    // making an interface enforce "no visible constructor" in its implementing classes 
    // - of course when Java finally implements full multiple inheritance some reflection 
    // technique might be used...
    NoVisibleConstructor addOrGetExisting( GettableSet<? extends NoVisibleConstructor> gettableSet );
};

public interface GettableSet<V extends NoVisibleConstructor> extends Set<V> {
    V getGenuineFromImpostor( V impostor ); // see below for naming
}

実装:

public class GettableHashSet<V extends NoVisibleConstructor> implements GettableSet<V> {
    private Map<V, V> map = new HashMap<V, V>();

    @Override
    public V getGenuineFromImpostor(V impostor ) {
        return map.get( impostor );
    }

    @Override
    public int size() {
        return map.size();
    }

    @Override
    public boolean contains(Object o) {
        return map.containsKey( o );
    }

    @Override
    public boolean add(V e) {
        assert e != null;
        V result = map.put( e,  e );
        return result != null;
    }

    @Override
    public boolean remove(Object o) {
        V result = map.remove( o );
        return result != null;
    }

    @Override
    public boolean addAll(Collection<? extends V> c) {
        // for example:
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
        map.clear();
    }

    // implement the other methods from Set ...
}

あなたのNoVisibleConstructorクラスは、次のようになります。

class SomeClass implements NoVisibleConstructor {

    private SomeClass( Object param1, Object param2 ){
        // ...
    }

    static SomeClass getOrCreate( GettableSet<SomeClass> gettableSet, Object param1, Object param2 ) {
        SomeClass candidate = new SomeClass( param1, param2 );
        if (gettableSet.contains(candidate)) {
            // obviously this then means that the candidate "fails" (or is revealed
            // to be an "impostor" if you will).  Return the existing element:
            return gettableSet.getGenuineFromImpostor(candidate);
        }
        gettableSet.add( candidate );
        return candidate;
    }

    @Override
    public NoVisibleConstructor addOrGetExisting( GettableSet<? extends NoVisibleConstructor> gettableSet ){
       // more elegant implementation-hiding: see below
    }
}

PSこのようなNoVisibleConstructorクラスの1つの技術的な問題:このようなクラスは本質的にfinalであることに反対する場合があり、これは望ましくない場合があります。実際には、常にダミーのパラメーターなしのprotectedコンストラクターを追加できます。

protected SomeClass(){
    throw new UnsupportedOperationException();
}

...少なくともサブクラスをコンパイルさせます。次にgetOrCreate()、サブクラスに別のファクトリメソッドを含める必要があるかどうかを検討する必要があります。

最後のステップは、このようなセットメンバーの抽象基本クラス(リストの場合は「要素」、セットの場合は「メンバー」)です(可能な場合は、クラスが制御下にないラッパークラスを使用するためのスコープ)。またはすでに基本クラスなどを持っています)、最大の実装非表示:

public abstract class AbstractSetMember implements NoVisibleConstructor {
    @Override
    public NoVisibleConstructor
            addOrGetExisting(GettableSet<? extends NoVisibleConstructor> gettableSet) {
        AbstractSetMember member = this;
        @SuppressWarnings("unchecked") // unavoidable!
        GettableSet<AbstractSetMembers> set = (GettableSet<AbstractSetMember>) gettableSet;
        if (gettableSet.contains( member )) {
            member = set.getGenuineFromImpostor( member );
            cleanUpAfterFindingGenuine( set );
        } else {
            addNewToSet( set );
        }
        return member;
    }

    abstract public void addNewToSet(GettableSet<? extends AbstractSetMember> gettableSet );
    abstract public void cleanUpAfterFindingGenuine(GettableSet<? extends AbstractSetMember> gettableSet );
}

...使用法はかなり明白です(あなたSomeClassstaticファクトリーメソッド内):

SomeClass setMember = new SomeClass( param1, param2 ).addOrGetExisting( set );

0

ハッシュコードの規約により、次のことが明確になります。

「2つのオブジェクトがObjectメソッドに従って等しい場合、2つのオブジェクトのそれぞれでhashCodeメソッドを呼び出すと、同じ整数の結果が生成される必要があります。」

だからあなたの仮定:

「明確にするために、equalsメソッドはオーバーライドされますが、すべてではなく1つのフィールドのみをチェックします。したがって、等しいと見なされる2つのFooオブジェクトは実際には異なる値を持つ可能性があるため、fooだけを使用することはできません。」

間違っており、あなたは契約を破っています。Setインターフェースの「contains」メソッドを見ると、次のようになります。

boolean contains(Object o);
このセットに指定された要素が含まれている場合はtrueを返します。より正式には、このセットにo == nullのような要素「e」が含まれている場合にのみtrueを返します。e == null:o.equals(e)

目的を達成するには、マップを使用してキーを定義し、オブジェクトが互いにどのように異なるか、または等しいかを定義するキーとともに要素を格納できます。


-2

この状況に対処できるクイックヘルパーメソッド:

<T> T onlyItem(Collection<T> items) {
    if (items.size() != 1)
        throw new IllegalArgumentException("Collection must have single item; instead it has " + items.size());

    return items.iterator().next();
}

8
この回答が質問に答えない、または何らかの方法で対応しようとしないため、この回答が非常に多くの賛成票を得ているのは非常に奇妙です。
David Conrad

-2

以下はアプローチです

   SharedPreferences se_get = getSharedPreferences("points",MODE_PRIVATE);
   Set<String> main = se_get.getStringSet("mydata",null);
   for(int jk = 0 ; jk < main.size();jk++)
   {
      Log.i("data",String.valueOf(main.toArray()[jk]));
   }

-2

配列を使用してみてください:

ObjectClass[] arrayName = SetOfObjects.toArray(new ObjectClass[setOfObjects.size()]);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.