Java 값 쌍 모음? (튜플?)


345

예를 들어 Java에 맵의 각 항목 유형을 정의 할 수있는 Map이있는 방법이 좋습니다 <String, Integer>.

내가 찾고있는 것은 컬렉션의 각 요소가 값 쌍인 컬렉션 유형입니다. 쌍의 각 값은 선언시 정의 된 고유 한 유형 (위의 문자열 및 정수 예제)을 가질 수 있습니다.

컬렉션은 주어진 순서를 유지하며 값 중 하나를 맵에서와 같이 고유 키로 취급하지 않습니다.

본질적으로 유형의 ARRAY <String,Integer>또는 다른 2 가지 유형 을 정의 할 수 있기를 원합니다 .

나는 2 개의 변수만으로 클래스를 만들 수는 있지만 지나치게 장황한 것처럼 보입니다.

또한 2D 배열을 사용할 수 있다는 것을 알고 있지만 사용해야하는 다른 유형으로 인해 OBJECT 배열을 만들어야하며 항상 캐스팅해야합니다.

컬렉션에 쌍만 저장하면되므로 항목 당 두 개의 값만 필요합니다. 수업 경로를 거치지 않고 이와 같은 것이 있습니까? 감사!


구아바에도 이것에 대한 수업이 있을지 궁금합니다.
시코 르 스키

구아바는 꽤 반 Pair은 아니며, 구글의 사람들은 훨씬 더 나은 대안 인 Auto / Value 를 만들기 위해 갔다 . 적절한 equals / hashCode 의미를 사용하여 올바른 형식의 값 형식 클래스 를 쉽게 만들 수 있습니다 . Pair다시 는 유형이 필요하지 않습니다 !
dimo414

답변:


255

Pair 클래스는 독자적으로 작성하기에 충분히 쉬운 "gimme"제네릭 예제 중 하나입니다. 예를 들어, 내 머리 꼭대기에서 :

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
음 ... 아니에요 필드는 최종으로 표시되므로 재 할당 할 수 없습니다. 'left'와 'right'는 변경할 수 있기 때문에 스레드 안전하지 않습니다. getLeft () / getRight ()가 방어 복사본을 반환하지 않으면 (이 경우에는 쓸모가 없음) 큰 문제가 무엇인지 알 수 없습니다.
무법자 프로그래머

17
hashCode ()는 왼쪽과 오른쪽이 바뀌면 동일한 값을 제공합니다. 아마 :long l = left.hashCode() * 2654435761L; return (int)l + (int)(l >>> 32) + right.hashCode();
karmakaze

68
따라서 올바르게 이해하면 간단한 쌍 클래스를 롤아웃하면 구문 오류, subpar hashCode 메소드, null 포인터 예외, compareTo 메소드, 디자인 질문이 발생하지 않습니다. 아파치 공통에 존재하는 동안 사람들은 여전히이 클래스 롤아웃을 옹호합니다. JAR을 포함하지 않고 휠 재발 명을 중단하려면 코드를 복사하십시오!
퀴젤

38
"자신이 작성하기에 충분히 쉽다"는 것은 무엇을 의미합니까? 그건 끔찍한 소프트웨어 공학. MyPair와 SomeoneElsesPair간에 변환하기위한 N ^ 2 어댑터 클래스도 스스로 작성하기에 충분히 쉬운 것으로 간주됩니까?
djechlin

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입니다.
Basil Bourque

3
이것은 자기 구현보다 낫습니다. 구현하기 쉽다는 사실은 매번 구현하기위한 변명이 아닙니다.
pevogam

6
나는 그것을 "표준"이라고 생각하지 않을 것입니다. Entry키-값 쌍이되어야합니다. 그러나 그것은 진정한 튜플로서 약점을 가지고 있습니다. 예를 들어 요소의 코드를 xors로 hashcode구현 SimpleEntry하면와 <a,b>같은 값으로 해시됩니다 <b,a>. 튜플 구현은 종종 사전 식으로 정렬하지만 SimpleEntry 구현하지는 않습니다 Comparable. 그러니 조심하세요 ...
Gene

167

자바 9+

Java 9에서는 간단히 다음과 같이 쓸 수 있습니다 Map.entry(key, value) . 불변 쌍을 만듭니다.

참고 : 이 방법은 키나 값을 null로 허용하지 않습니다. 예를 들어 null 값을 허용하려면 이것을 다음과 같이 변경하십시오 Map.entry(key, Optional.ofNullable(value)).


자바 8+

Java 8에서는보다 일반적인 용도 javafx.util.Pair를 사용하여 불변의 직렬화 가능 쌍을 작성할 수 있습니다. 이 클래스 null 키와 null 값을 허용합니다. (Java 9에서이 클래스는 javafx.base모듈에 포함되어 있습니다 ). 편집 : Java 11부터 JavaFX가 JDK에서 분리되었으므로 추가 maven 아티팩트 org.openjfx : javafx-base가 필요합니다.


자바 6+

Java 6 이상 AbstractMap.SimpleImmutableEntry에서는 불변 쌍 또는 AbstractMap.SimpleEntry값을 변경할 수있는 쌍에 더 자세한 정보 를 사용할 수 있습니다. 이 클래스는 널 키와 널 값도 허용하며 직렬화 가능합니다.


기계적 인조 인간

Android 용으로 쓰고 있다면 Pair.create(key, value)불변 쌍을 만들기 위해 사용하십시오 .


아파치 커먼즈

Apache Commons LangPair.of(key, value)불변의 비교 가능한 직렬화 쌍을 만드는 데 도움이 됩니다.


이클립스 컬렉션

기본 요소가 포함 된 쌍을 사용하는 경우 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

2
Eclipse Collections에는 Pair객체 를위한 인터페이스 도 있으며이를 호출하여 인스턴스화 할 수 있습니다 Tuples.pair(object1, object2). eclipse.org/collections/javadoc/9.2.0/org/eclipse/collections/…
Donald Raab

2
이것은 가장 진부한 답변입니다. 사용 가능한 모든 구현. 매우 철저하고 감사합니다!
Mike

안녕하세요 @Hans 목록을 사용하고 List<Pair<Integer, String> listOfTuple있습니다. 어떻게 사용 listOfTuple.add()합니까? 내가 할 경우- listOfTuple.add(Pair<someInteger, someString>);작동하지 않습니다. 미리 감사드립니다.
Me_developer

안드로이드 버전은 단위 테스트에서 사용할 수 없습니다, 그것은 실제로 유용하지 않습니다 ...
OznOg


31

Apache 공통 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> 클래스를 작성하고 이것을 배열 또는 목록에서 사용할 수 있습니다. 예, 클래스를 작성해야하지만 모든 유형에 대해 동일한 클래스를 재사용 할 수 있으므로 한 번만 수행하면됩니다.


그 예를보고 싶습니다!
DivideByHero

1
Dan, 그것에 대한 나쁜 점은 유형 지우기 때문에 예를 들어 Pair <String, Integer> 만 받아 들일 수 없다는 것입니다. 그러나 Java도 마찬가지입니다.
Johannes Weiss


나는 이것이 일반 배열에는 효과가 없다고 생각하지만 다른 컬렉션에는 분명히 효과가 있습니다.
무법자 프로그래머

@ 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 라이브러리가 공통적 인 언어 또는 다른 타사를 사용하여 이러한 기본 작업을 수행 해야하는 일이 너무 드문 경우에는 부끄러운 일입니다. 스칼라로 업그레이드해야하는 또 다른 이유는 ...


6

나는 당신이 그냥 사용하고 싶지 않은지 물었을 것 List<Pair<T, U>>입니까? 물론 JDK에는 Pair <> 클래스가 없습니다. 그러나 빠른 Google은 Wikipediaforums.sun.com 에서 하나를 발견 했습니다 . 건배


6

설명한대로 선호되는 솔루션은 쌍 목록 (즉, 목록)입니다.

이를 위해 컬렉션에 사용할 Pair 클래스를 만듭니다. 이것은 코드베이스에 추가 할 수있는 유용한 유틸리티 클래스입니다.

일반적인 Pair 클래스와 유사한 기능을 제공하는 Sun JDK에서 가장 가까운 클래스는 AbstractMap.SimpleEntry입니다. 자신 만의 Pair 클래스를 만들지 않고이 클래스를 사용할 수 있지만, 어색한 제한을 가지고 살아야하지만 대부분의 사람들은 이것을 SimpleEntry의 의도 된 역할이 아니라고 생각합니다. 예를 들어 SimpleEntry에는 "setKey ()"메소드와 기본 생성자가 없으므로 너무 제한적일 수 있습니다.

컬렉션은 단일 유형의 요소를 포함하도록 설계되었습니다. Map과 같은 관련 유틸리티 인터페이스는 실제로 Collection이 아닙니다 (예 : Map은 Collection 인터페이스를 구현하지 않습니다). Pair는 Collection 인터페이스도 구현하지 않지만 더 큰 데이터 구조를 구축하는 데 유용한 클래스입니다.


이 솔루션은 일반적인 Pair <K, V>를 사용하는 "승리"솔루션보다 더 좋습니다. 요청 된 모든 것을 수행하고 즉시 제공됩니다. 나는 이것을 구현에 사용한다.
Sauer

5

이것은 JavaHelp4u의 코드를 기반으로합니다.

덜 장황하고 한 줄로하는 방법과 물건을 반복하는 방법을 보여줍니다.

//======>  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

PairJava에는 클래스 가 없지만 꽤 비슷한 것이 있습니다.Map.Entry

Map.Entry 문서

이것은 (아주 약간 단순화) 무엇입니까 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")})이 있다고 가정 해 봅시다. 각 사람이지도의 열쇠이며 한 사람당 하나의 속성 만 허용하므로지도에 쌍으로 저장할 수 없습니다.
manuelvigarcia


0

com.sun.tools.javac.util.Pair는 어떻습니까?


7
이 유형은 tools.jar에 있습니다. javac 컴파일러의 "Sun"구현의 일부입니다. JDK의 일부로 만 배포되며 다른 공급 업체 구현에는 없을 수 있으며 공개 API의 일부가 아닐 수 있습니다.
McDowell

0

키 / 값 쌍에 대해 이야기 할 때 가장 먼저 생각해야 할 것은 스트림 / 파일에 항목을 저장하고로드 할 수 있는 속성 클래스 입니다.


0

프로젝트 리액터 (io.projectreactor : reactor-core)에는 n-Tuples에 대한 고급 지원이 있습니다.

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

당신이 얻을 수 t.getT1(), t.getT2(), ...도 튜플 요소를 매핑 할 수 있습니다 스트림 또는 플럭스 당신과 함께 특히 :

Stream<Tuple2<String, Integer>> s;
s.map(t -> t.mapT2(i -> i + 2));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.