値ペアのJavaコレクション?(タプル?)


345

たとえば、Javaには、マップ内の各エントリのタイプを定義できるマップがあります<String, Integer>

私が探しているのは、コレクションの各要素が値のペアであるコレクションのタイプです。ペアの各値は、宣言時に定義される独自のタイプ(上記のStringおよびIntegerの例のように)を持つことができます。

コレクションは指定された順序を維持し、値の1つを(マップのように)一意のキーとして扱いません。

基本的に、タイプ<String,Integer>または他の2つのタイプのARRAYを定義できるようにしたいと考えています。

2つの変数のみを含むクラスを作成できることはわかっていますが、それは過度に冗長に見えます。

2D配列を使用できることも理解していますが、使用する必要があるさまざまなタイプのため、それらをOBJECTの配列にする必要があり、その後、常にキャストする必要があります。

コレクションにペアを保存するだけでよいので、エントリごとに2つの値しか必要ありません。クラスのルートに行かなくても、このようなものが存在しますか?ありがとう!


グアバもこれのためのクラスがあるかもしれないのだろうか。
シコルスキ2013

グアバはかなりアンチですPair、そして、Googleの人々ははるかに良い代替を作成するために行きました-Auto / Value。適切なequals / hashCodeセマンティクスを使用して、適切に型指定された値型クラスを簡単に作成できます。Pairタイプはもう必要ありません!
dimo414 2017

回答:


255

Pairクラスは、「gimme」ジェネリックの例の1つで、自分で簡単に書くことができます。たとえば、頭の上から:

public class Pair<L,R> {

  private final L left;
  private final R right;

  public Pair(L left, R right) {
    assert left != null;
    assert right != null;

    this.left = left;
    this.right = right;
  }

  public L getLeft() { return left; }
  public R getRight() { return right; }

  @Override
  public int hashCode() { return left.hashCode() ^ right.hashCode(); }

  @Override
  public boolean equals(Object o) {
    if (!(o instanceof Pair)) return false;
    Pair pairo = (Pair) o;
    return this.left.equals(pairo.getLeft()) &&
           this.right.equals(pairo.getRight());
  }

}

そして、はい、これはネット上の複数の場所に存在し、完全性と機能の程度はさまざまです。(上記の私の例は不変であることを意図しています。)


17
私はこれが好きですが、左右のフィールドをパブリックにすることについてどう思いますか?Pairクラスにロジックが関連付けられることはなく、すべてのクライアントが「左」と「右」にアクセスする必要があることは明らかなので、簡単にしてみませんか?
アウトロープログラマ、

43
ええと...そうではありません。フィールドは最終としてマークされているため、再割り当てできません。また、「左」と「右」は変更可能であるため、スレッドセーフではありません。getLeft()/ getRight()が防御コピー(この場合は役に立たない)を返さない限り、大したことはわかりません。
アウトロープログラマ、

17
左と右を入れ替えても、hashCode()はそのままの値を与えることに注意してください。おそらく:long l = left.hashCode() * 2654435761L; return (int)l + (int)(l >>> 32) + right.hashCode();
karmakaze 2012

68
したがって、私が正しく理解している場合、単純なペアクラスをロールアウトすると、構文エラー、subpar hashCodeメソッド、nullポインタ例外、compareToメソッドなし、設計に関する質問が発生し、Apacheコモンズに存在するこのクラスをロールアウトすることを推奨します。JARを含めたくないが、ホイールの再発明を中止する場合は、コードをコピーしてください。
cquezel 2013年

38
「自分で書くのに十分簡単」とはどういう意味ですか?それはひどいソフトウェアエンジニアリングです。MyPairとSomeoneElsesPairの間で変換するN ^ 2アダプタークラスも、自分で書くのに十分簡単と考えられていますか?
djechlin 2013年

299

AbstractMap.SimpleEntry

あなたがこれを探しているのは簡単です:

java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();

どのように記入できますか?

java.util.Map.Entry<String,Integer> pair1=new java.util.AbstractMap.SimpleEntry<>("Not Unique key1",1);
java.util.Map.Entry<String,Integer> pair2=new java.util.AbstractMap.SimpleEntry<>("Not Unique key2",2);
pairList.add(pair1);
pairList.add(pair2);

これにより、以下が簡素化されます。

Entry<String,Integer> pair1=new SimpleEntry<>("Not Unique key1",1);
Entry<String,Integer> pair2=new SimpleEntry<>("Not Unique key2",2);
pairList.add(pair1);
pairList.add(pair2);

また、createEntryメソッドを使用して、冗長性をさらに次のように減らすことができます。

pairList.add(createEntry("Not Unique key1", 1));
pairList.add(createEntry("Not Unique key2", 2));

ArrayListは最終版ではないため、サブクラス化してofメソッド(および前述のcreateEntryメソッド)を公​​開し、構文的に簡潔にすることができます。

TupleList<java.util.Map.Entry<String,Integer>> pair = new TupleList<>();
pair.of("Not Unique key1", 1);
pair.of("Not Unique key2", 2);

11
参考:提案されSimpleEntryているのは、兄弟クラスを省略setValueして不変にするメソッドです。したがって、名前SimpleImmutableEntry
バジルブルク

3
これは自己実装よりも優れています。簡単に実装できるということは、毎回実装するための言い訳にはなりません。
pevogam 2017年

6
「標準」だとは思いません。Entryキーと値のペアであることを意味し、それで問題ありません。しかし、それには真のタプルとしての弱点があります。たとえば、要素のコードをxorsするだけのhashcode実装SimpleEntryなので<a,b>、と同じ値にハッシュします<b,a>。タプルの実装でSimpleEntry は、辞書順にソートされることがよくありますが、は実装されていませんComparable。したがって、注意してください...
Gene

167

Java 9以降

Java 9では、次のように書くだけでMap.entry(key, value) 不変のペアを作成できます。

注:このメソッドでは、キーまたは値をnullにすることはできません。たとえば、null値を許可する場合は、これを次のように変更しますMap.entry(key, Optional.ofNullable(value))


Java 8以降

Java 8では、より汎用的な目的javafx.util.Pairを使用して、不変でシリアル化可能なペアを作成できます。このクラス nullキーとnull値を許可します。(Java 9では、このクラスはjavafx.baseモジュールに含まれています)。編集:Java 11以降、JavaFXはJDKから切り離されているため、追加のMavenアーティファクトorg.openjfx:javafx-baseが必要になります。


Java 6以降

Java 6以降でAbstractMap.SimpleImmutableEntryは、不変のペア、またはAbstractMap.SimpleEntry値を変更できるペアの詳細を使用できます。これらのクラスはnullキーとnull値も許可し、シリアル化可能です。


アンドロイド

Android向けPair.create(key, value)に作成している場合は、を使用して不変ペアを作成します。


Apache Commons

Apache Commons Langは、Pair.of(key, value)不変で比較可能な直列化可能なペアを作成するのに役立ちます。


Eclipseコレクション

プリミティブを含むペアを使用している場合、Eclipseコレクションは非常に効率的なプリミティブペアクラスを提供し、非効率的な自動ボックス化と自動ボックス化解除をすべて回避します。

たとえば、PrimitiveTuples.pair(int, int)を作成しIntIntPairたり、PrimitiveTuples.pair(float, long)を作成したりできますFloatLongPair


プロジェクトロンボク

Project Lombokを使用すると、次のように記述するだけで不変ペアクラスを作成できます。

@Value
public class Pair<K, V> {
    K key;
    V value;
}

ロンボクは、コンストラクタ、ゲッター、に記入しますequals()hashCode()と、toString()生成されたバイトコードに自動的にあなたのための方法。コンストラクターの代わりに静的なファクトリーメソッド(aなど)が必要な場合はPair.of(k, v)、アノテーションを次のように変更します@Value(staticConstructor = "of")


さもないと

上記の解決策のいずれもボートをフロートさせない場合は、次のコードをコピーして貼り付けることができます(受け入れられた回答にリストされているクラスとは異なり、NullPointerExceptionsから保護されます)。

import java.util.Objects;

public class Pair<K, V> {

    public final K key;
    public final V value;

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public boolean equals(Object o) {
        return o instanceof Pair && Objects.equals(key, ((Pair<?,?>)o).key) && Objects.equals(value, ((Pair<?,?>)o).value);
    }

    public int hashCode() {
        return 31 * Objects.hashCode(key) + Objects.hashCode(value);
    }

    public String toString() {
        return key + "=" + value;
    }
}

3
ただし、JavaFXはデスクトップ専用であり、非デスクトップ環境(サーバーなど)に不要な依存関係を追加します。
foo 2017年

2
EclipseコレクションにはPairオブジェクトのインターフェースもあり、を呼び出すことでインスタンス化できますTuples.pair(object1, object2)eclipse.org/collections/javadoc/9.2.0/org/eclipse/collections/...
ドナルド・ラーブ

2
これは最も真にJava風の答えのように感じられます。利用可能なすべての実装。本当にありがとうございます。
Mike

こんにちは@Hansリストを使用していますList<Pair<Integer, String> listOfTuple。どうやって使うのlistOfTuple.add()?私がやるなら- listOfTuple.add(Pair<someInteger, someString>);これはうまくいきません。前もって感謝します。
Me_developer

Androidバージョンは単体テストでは利用できないため、実際には役に立ちません...
OznOg


31

Apache common lang3には、このスレッドで言及されているPairクラスと他のいくつかのライブラリがあります。Java のC ++ Pair <L、R>に相当するものは何ですか?

元の質問の要件に一致する例:

List<Pair<String, Integer>> myPairs = new ArrayList<Pair<String, Integer>>();
myPairs.add(Pair.of("val1", 11));
myPairs.add(Pair.of("val2", 17));

//...

for(Pair<String, Integer> pair : myPairs) {
  //following two lines are equivalent... whichever is easier for you...
  System.out.println(pair.getLeft() + ": " + pair.getRight());
  System.out.println(pair.getKey() + ": " + pair.getValue());
}

1
これは、Apache Commonsが利用可能な場合、最も簡単なオプションです。
Kip


15

「Apache Commons Lang 3」Pairクラスと関連サブクラスはどうですか?

    import org.apache.commons.lang3.tuple.ImmutablePair;
    import org.apache.commons.lang3.tuple.Pair;
    ...
    @SuppressWarnings("unchecked")
    Pair<String, Integer>[] arr = new ImmutablePair[]{
            ImmutablePair.of("A", 1),
            ImmutablePair.of("B", 2)};

    // both access the 'left' part
    String key = arr[0].getKey();
    String left = arr[0].getLeft();

    // both access the 'right' part
    Integer value = arr[0].getValue();
    Integer right = arr[0].getRight();

ImmutablePairペアの値を変更できない特定のサブクラスですが、セマンティクスが異なる他の実装もあります。あなたがそれらを必要とするなら、これらはMaven座標です。

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>

11

汎用のPair <A、B>クラスを記述して、これを配列またはリストで使用できます。はい、クラスを作成する必要がありますが、同じクラスをすべてのタイプで再利用できるため、1回だけ実行する必要があります。


その例を見たいです!
DivideByHero 2009

1
ダン、それの悪い点は、型の消去のために、たとえばPair <String、Integer>だけを受け入れることができないということです。しかし、そうするJava ...である
ヨハネス・ヴァイス


これは単純な配列では機能しないと思いますが、他のコレクションでも機能します。
アウトロープログラマ、

@Outlaw Programmer:良い点、配列で使用できますが、汎用配列を作成するためにハックを使用する必要があるため、醜いです。
Dan Dyer、

7

他の答えを拡張すると、ジェネリックな不変ペアは静的メソッドを持つ必要があり、コンストラクターの呼び出しでコードが乱雑になるのを防ぎます。

class Pair<L,R> {
      final L left;
      final R right;

      public Pair(L left, R right) {
        this.left = left;
        this.right = right;
      }

      static <L,R> Pair<L,R> of(L left, R right){
          return new Pair<L,R>(left, right);
      }
}

静的メソッドに「of」または「pairOf」と名前を付けると、次のいずれかを記述できるため、コードが流暢になります。

    list.add(Pair.of(x,y)); // my preference
    list.add(pairOf(x,y)); // use with import static x.y.Pair.pairOf

コアJavaライブラリが非常にまばらで、そのような基本的なことを行うにはcommons-langまたは他のサードパーティを使用する必要があるというのは、本当に残念です。scalaにアップグレードするもう1つの理由...


6

私はあなたが単に使用したくないかどうか尋ねるつもりでしたList<Pair<T, U>>か?しかしもちろん、JDKにはPair <>クラスがありません。しかし、すぐにGoogleがWikipediaforums.sun.comの両方で見つけました。乾杯


6

あなたが説明したように、それはペアのリスト(すなわちリスト)です。

これを行うには、コレクションで使用するPairクラスを作成します。これは、コードベースに追加するのに便利なユーティリティクラスです。

典型的なPairクラスと同様の機能を提供するSun JDKの最も近いクラスは、AbstractMap.SimpleEntryです。独自のPairクラスを作成するのではなく、このクラスを使用することもできますが、厄介な制限に耐える必要があり、SimpleEntryの本来の役割ではないため、ほとんどの人はこれを嫌うでしょう。たとえば、SimpleEntryには「setKey()」メソッドもデフォルトコンストラクタもないため、制限が多すぎる場合があります。

コレクションは単一のタイプの要素を含むように設計されていることに注意してください。Mapなどの関連ユーティリティインターフェイスは実際にはコレクションではありません(つまり、Mapはコレクションインターフェイスを実装していません)。PairはCollectionインターフェースも実装しませんが、より大きなデータ構造を構築する上で明らかに有用なクラスです。


このソリューションは、一般的なPair <K、V>を使用した「勝つ」ソリューションよりも優れていると思います。それは要求されたすべてを行い、箱から出して来ます。私はこれを私の実装に使用します。
Sauer

5

これはJavaHelp4uのコードに基づいています。

冗長性が低く、1行で実行する方法とループする方法を示します。

//======>  Imports
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

//======>  Single Entry
SimpleEntry<String, String> myEntry = new SimpleEntry<String, String>("ID", "Text");
System.out.println("key: " + myEntry.getKey() + "    value:" + myEntry.getValue());
System.out.println();

//======>  List of Entries
List<Entry<String,String>> pairList = new ArrayList<>();

//-- Specify manually
Entry<String,String> firstButton = new SimpleEntry<String, String>("Red ", "Way out");
pairList.add(firstButton);

//-- one liner:
pairList.add(new SimpleEntry<String,String>("Gray", "Alternate route"));  //Ananomous add.

//-- Iterate over Entry array:
for (Entry<String, String> entr : pairList) {
    System.out.println("Button: " + entr.getKey() + "    Label: " + entr.getValue());
}


4

次のようなクラスを作成するだけです

class tuples 
{ 
int x;
int y;
} 

次に、タプルのこのオブジェクトのリストを作成します

List<tuples> list = new ArrayList<tuples>();

そのため、他の新しいデータ構造も同じ方法で実装できます。


4

Pairつまり、Javaにはクラスがありませんが、かなりよく似たものがあります。Map.Entry

Map.Entryドキュメント

これは(かなり単純化して)what HashMap、または実際には任意のMapストアです。

Map値を格納するインスタンスを作成して、エントリセットを取得できます。あなたは最終Set<Map.Entry<K,V>>的にあなたが望むものであるもので終わるでしょう。

そう:

public static void main(String []args)
{    
    HashMap<String, Integer> values = new HashMap<String,Integer>();
    values.put("A", 235);//your custom data, the types may be different
    //more data insertions....
    Set<Map.Entry<String,Integer>> list = values.entrySet();//your list 
    //do as you may with it
}

このオプションには、一意のキーの問題があります。人の属性があるとしましょう(例:{(person1、 "blue-eyed")、(person1、 "red-haired"、(person2、 "shortsighted")、(person2、 "quick-thinker")})。各人がマップのキーであり、1人につき1つの属性しか許可しないため、それらをマップにペアとして保存することはできません
manuelvigarcia


0

com.sun.tools.javac.util.Pairはどうですか?


7
このタイプは、javacコンパイラの「Sun」実装の一部であるtools.jarにあります。これはJDKの一部としてのみ配布され、他のベンダーの実装には存在しない可能性があり、パブリックAPIの一部になる可能性は低いです。
McDowell

0

キーと値のペアについて話すときに最初に頭に浮かぶのは、アイテムをストリーム/ファイルに保存およびロードできるプロパティクラスです。


0

プロジェクトReactor(io.projectreactor:reactor-core)では、nタプルの高度なサポートがあります。

Tuple2<String, Integer> t = Tuples.of("string", 1)

そこで、t.getT1(), t.getT2(), ...特にStreamまたはFluxを使用して、タプル要素をマッピングすることもできます。

Stream<Tuple2<String, Integer>> s;
s.map(t -> t.mapT2(i -> i + 2));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.