Java에서 C ++ Pair <L, R>에 해당하는 것은 무엇입니까?


671

Pair<L,R>Java 가없는 이유가 있습니까? 이 C ++ 구문과 동등한 것은 무엇입니까? 오히려 내 자신을 다시 구현하는 것을 피하고 싶습니다.

것 같다 1.6 비슷한 (제공 AbstractMap.SimpleEntry<K,V>)하지만,이 모습이 꽤 뒤얽힌.


7
AbstractMap.SimpleEntry복잡한가?
CurtainDog

27
namig로 인해 하나의 키와 하나의 값을 임의로 명명합니다.
Enerccio


2
@sffc JavaFX는 JDK7의 기본 클래스 경로에 없으므로 JFX 런타임 라이브러리를 수동으로 추가해야합니다.
코드 Rehn

3
@ Enerccio : 그래서, 당신은 실제로 "key"와 "value"가 "first"와 "second"는 임의적이지 않다고 진술합니다. 그렇다면 이것이 SDK에 그러한 클래스가없는 좋은 이유 중 하나입니다. "적절한"명명에 대한 영원한 논쟁이있을 것입니다.
fdreger

답변:


400

에 스레드comp.lang.java.help , 헌터 Gratzner은의 존재에 대한 몇 가지 인수를 제공 Pair자바 구문을. 주요 주장은 클래스 Pair가 두 값 사이의 관계에 대한 의미를 전달하지 않는다는 것입니다 ( "first"와 "second"의 의미는 무엇입니까?).

더 좋은 방법은 Mike가 제안한 것과 같이 클래스로 만든 각 응용 프로그램에 대해 매우 간단한 클래스를 작성하는 것 Pair입니다. Map.Entry이름에 의미가있는 쌍의 예입니다.

요약하자면, 제 생각에는 수행해야 할 일에 대해 아무것도 알려주지 않는 제네릭보다는 클래스 Position(x,y), 클래스 Range(begin,end)및 클래스 를 갖는 Entry(key,value)것이 좋습니다 Pair(first,second).


143
Gratzner는 머리카락을 나누고 있습니다. 우리는 클래스에서 캡슐화하지 않고 기본 또는 내장 클래스로 단일 값을 반환하게되어 매우 기쁩니다. 우리가 십여 개의 요소를 돌려 보내려면 아무도 자신의 반을 가지고 있지 않을 것입니다. 가운데 어딘가에 (퍼지) 구분선이 있습니다. 나는 우리의 도마뱀 두뇌가 쉽게 쌍에 대처할 수 있다고 생각합니다.
Ian

25
나는 Ian에 동의합니다. Java를 사용하면 int를 반환 할 수 있습니다. 별명을 사용할 때마다 int에 대한 별명을 작성하도록 강요하지는 않습니다. 쌍은 크게 다르지 않습니다.
Clément

5
페어를 로컬 변수에 직접 풀거나 두 개의 인수를 취하는 메소드로 전달할 수 있다면 Pair는 유용한 클래스가됩니다. 이렇게 압축을 풀 수 없으므로 의미있는 클래스를 만들고 값을 함께 유지하는 것이 그리 나쁘지 않습니다. 그리고 한계에도 불구하고 정말로 짝을 원한다면 Object [2] + casts :-)가 있습니다.
marcus

문제는 Gratzner에 동의하지 않으면 여러 곳에 Pair 구현이 있다는 것입니다. Apache Commons와 Guava에는 모두 IIRC가 있습니다. 그것들을 사용하십시오. 그러나 주요 Java 라이브러리에 무언가를 넣으라는 것은 그것이 고귀하고 승인 된 일을하는 방식 (대문자 사용)이며 사람들이 동의하지 않기 때문에 거기에 두지 않아야합니다. 구식 라이브러리에는 틈새가 충분하므로 불필요하게 더 많이 넣지 마십시오.
Haakon Løtveit

1
@Dragas 내가 한 쌍의 값이 필요할 때 Java가 아닙니다 ... 심각하게?
idclev 463035818

156

이것은 자바입니다. 설명 클래스 및 필드 이름을 사용하여 사용자 정의 된 Pair 클래스를 작성해야하며 hashCode () / equals ()를 작성하거나 Comparable을 반복해서 구현하여 휠을 재발 명 할 것이라는 점을 염두에 두지 마십시오.


61
그것은 "왜"라는 질문에 대답하지 않습니다. ( 'this is java'라고 답하지 않는 한)
Nikita Rybak

127
자바의 장황을 조롱하는 +1. 실제로 질문에 대답하지 않은 경우 -1입니다.
베넷 맥 엘위

19
Java 클래스는 Pair 클래스가 포함 된 Apache Commong Lang을 가리켰다면 좋을 것입니다.
haylem

6
또는 당신은 사용할 수 있습니다SimpleImmutableEntry
CurtainDog

33
첫 번째 문장은 "왜?"라는 질문에 대답합니다. 이것은 자바입니다.
masterziv

103

HashMap 호환 페어 클래스 :

public class Pair<A, B> {
    private A first;
    private B second;

    public Pair(A first, B second) {
        super();
        this.first = first;
        this.second = second;
    }

    public int hashCode() {
        int hashFirst = first != null ? first.hashCode() : 0;
        int hashSecond = second != null ? second.hashCode() : 0;

        return (hashFirst + hashSecond) * hashSecond + hashFirst;
    }

    public boolean equals(Object other) {
        if (other instanceof Pair) {
            Pair otherPair = (Pair) other;
            return 
            ((  this.first == otherPair.first ||
                ( this.first != null && otherPair.first != null &&
                  this.first.equals(otherPair.first))) &&
             (  this.second == otherPair.second ||
                ( this.second != null && otherPair.second != null &&
                  this.second.equals(otherPair.second))) );
        }

        return false;
    }

    public String toString()
    { 
           return "(" + first + ", " + second + ")"; 
    }

    public A getFirst() {
        return first;
    }

    public void setFirst(A first) {
        this.first = first;
    }

    public B getSecond() {
        return second;
    }

    public void setSecond(B second) {
        this.second = second;
    }
}

136
아마도 세터를 삭제하고 첫 번째와 두 번째를 최종적으로 만들어 쌍을 변경할 수 없게 만들고 싶을 것입니다. (해시 키로 구성 요소를 사용한 후 누군가가 구성 요소를 변경하면 이상한 일이 발생합니다).
Thilo

21
toString () 메서드에서 "("+ first.toString () + ","+ second.toString () + ")"을 반환하면 NullPointerException이 발생할 수 있습니다. 더 나은 : return "("+ first + ","+ second + ")";
Juha Syrjälä

6
또한 쌍을 "최종"으로 표시하거나 첫 번째 줄을 'if (other! = null && this.getClass () == other.getClass ())'로 변경하십시오.
sargas

8
임의의 nooby 질문에 대해 죄송하지만 생성자에서 super ()를 호출하는 이유는 무엇입니까?
Ibrahim

6
@Ibrahim :이 경우에는 불필요한 것입니다 .— super()외출 했을 때의 동작은 정확히 같습니다 . 일반적으로 여기에있는 것처럼 선택 사항 인 경우 그냥 기울입니다.
Chris Jester-Young

53

내가 올릴 수있는 가장 짧은 쌍은 롬복을 사용하여 다음과 같습니다 .

@Data
@AllArgsConstructor(staticName = "of")
public class Pair<F, S> {
    private F first;
    private S second;
}

@arturh (비교 제외) 의 대답 의 모든 이점을 가지고 hashCode있으며 equals, toString및 정적 "생성자"가 있습니다.


맵시 있는! 그것을 좋아했다!
Ahmet Ipkin


31

Pair with를 구현하는 또 다른 방법입니다.

  • 공개 불변 필드, 즉 간단한 데이터 구조.
  • 유사한.
  • 간단한 해시와 같습니다.
  • 간단한 팩토리이므로 유형을 제공 할 필요가 없습니다. 예를 들어 Pair.of ( "hello", 1);

    public class Pair<FIRST, SECOND> implements Comparable<Pair<FIRST, SECOND>> {
    
        public final FIRST first;
        public final SECOND second;
    
        private Pair(FIRST first, SECOND second) {
            this.first = first;
            this.second = second;
        }
    
        public static <FIRST, SECOND> Pair<FIRST, SECOND> of(FIRST first,
                SECOND second) {
            return new Pair<FIRST, SECOND>(first, second);
        }
    
        @Override
        public int compareTo(Pair<FIRST, SECOND> o) {
            int cmp = compare(first, o.first);
            return cmp == 0 ? compare(second, o.second) : cmp;
        }
    
        // todo move this to a helper class.
        private static int compare(Object o1, Object o2) {
            return o1 == null ? o2 == null ? 0 : -1 : o2 == null ? +1
                    : ((Comparable) o1).compareTo(o2);
        }
    
        @Override
        public int hashCode() {
            return 31 * hashcode(first) + hashcode(second);
        }
    
        // todo move this to a helper class.
        private static int hashcode(Object o) {
            return o == null ? 0 : o.hashCode();
        }
    
        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof Pair))
                return false;
            if (this == obj)
                return true;
            return equal(first, ((Pair) obj).first)
                    && equal(second, ((Pair) obj).second);
        }
    
        // todo move this to a helper class.
        private boolean equal(Object o1, Object o2) {
            return o1 == null ? o2 == null : (o1 == o2 || o1.equals(o2));
        }
    
        @Override
        public String toString() {
            return "(" + first + ", " + second + ')';
        }
    }

10
나는 정적 팩토리 메소드를 좋아한다 of. Google Guava의 불변 컬렉션을 상기시킵니다 .
Jarek Przygódzki

7
당신은 주조 어떤 점에 있습니다 o1Comparable아무것도 실제로 그 인터페이스를 구현하는 것입니다 나타냅니다에도 불구하고. 이것이 필수 인 경우 FIRSTtype 매개 변수는이어야합니다 FIRST extends Comparable<?>.
G_H

나는 자바 사람이 아니기 때문에, 나의 무지에 대해 용서해주십시오. 그러나 TODO 코멘트에서 어떤 종류의 도우미 수업을 생각하고 있었습니까?

3
31은 hashCode의 잘못된 상수입니다. 예를 들어 2D 맵에 Pair <Integer, Integer>로 키가 지정된 HashMap을 사용하면 충돌이 많이 발생합니다. 예를 들어 (a * 65497) ^ b가 더 적합합니다.
Michał Zieliński 2016 년

1
@MarioCarneiro ^는 힘이 아니라 xor입니다
Michał Zieliński

27

http://www.javatuples.org/index.html 은 어떻습니까? 매우 유용하다는 것을 알았습니다.

javatuples는 1에서 10 개의 요소로 구성된 튜플 클래스를 제공합니다.

Unit<A> (1 element)
Pair<A,B> (2 elements)
Triplet<A,B,C> (3 elements)
Quartet<A,B,C,D> (4 elements)
Quintet<A,B,C,D,E> (5 elements)
Sextet<A,B,C,D,E,F> (6 elements)
Septet<A,B,C,D,E,F,G> (7 elements)
Octet<A,B,C,D,E,F,G,H> (8 elements)
Ennead<A,B,C,D,E,F,G,H,I> (9 elements)
Decade<A,B,C,D,E,F,G,H,I,J> (10 elements)

6
재밌지 만, 내가 생각했던 것보다 최소한 5 개의 클래스가 더 있습니다.
maaartinus

3
@maaartinus 내가 사용하는 것보다 적어도 10 이상.
Boann

7
@Boann : 좋아, 나는 수정 유지. 나는 사용했었다PairTriplet 50 년마다 한 번씩 하고 상상할 수있었습니다 . 이제는 롬복을 사용하고 필요할 때마다 작은 4 라인 클래스를 만듭니다. "10이 너무 많음"이 정확합니다.
maaartinus

5
우리는 필요합니까 Bottom (0 element)수업이 합니까? :)
Earth Engine

2
와우 이거 못 생겼어 나는 그들이 명시 적으로 만들려고한다는 것을 알고 있지만 C #과 같은 매개 변수가 과부하 된 튜플은 더 좋을 것입니다.
arviman

12

사용하려는 대상에 따라 다릅니다. 그렇게하는 일반적인 이유는지도를 반복하기 위해서입니다 (Java 5 이상) :

Map<String, Object> map = ... ; // just an example
for (Map.Entry<String, Object> entry : map.entrySet()) {
  System.out.printf("%s -> %s\n", entry.getKey(), entry.getValue());
}

1
나는 사용자 정의 클래스 :이 경우에 도움이 될 모르겠어요
니키타 리박

31
"일반적인 이유는지도를 반복하기 위해서입니다." 정말?
베넷 맥 엘위

12

안드로이드는 Pair클래스 ( http://developer.android.com/reference/android/util/Pair.html )를 제공합니다 .

public class Pair<F, S> {
    public final F first;
    public final S second;

    public Pair(F first, S second) {
        this.first = first;
        this.second = second;
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Pair)) {
            return false;
        }
        Pair<?, ?> p = (Pair<?, ?>) o;
        return Objects.equal(p.first, first) && Objects.equal(p.second, second);
    }

    @Override
    public int hashCode() {
        return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
    }

    public static <A, B> Pair <A, B> create(A a, B b) {
        return new Pair<A, B>(a, b);
    }
}

1
Objects.equal(..)구아바 도서관이 필요합니다.
Markus L

3
Objects.equals(...)2011 년 이후 Java (1.7) 이후로 변경하십시오 .
AndrewF

9

가장 큰 문제는 사람이 A와 B에 불변성을 보장 할 수 없습니다 아마도 (참조 유형 매개 변수는 불변을 보장하기 위하여 어떻게 그렇게) hashCode()같은 쌍에 대한 일관성없는 결과를 제공 할 수 있습니다 예를 들어 콜렉션에 삽입 (이 정의되지 않은 동작을 줄 것 변경 가능한 필드의 관점에서 등가 정의 참조 ). 특정 (일반적이지 않은) 페어 클래스의 경우 프로그래머는 A와 B를 불변으로 신중하게 선택하여 불변성을 보장 할 수 있습니다.

어쨌든 @PeterLawrey의 답변 (java 1.7)에서 generic의 경고를 지우십시오.

public class Pair<A extends Comparable<? super A>,
                    B extends Comparable<? super B>>
        implements Comparable<Pair<A, B>> {

    public final A first;
    public final B second;

    private Pair(A first, B second) {
        this.first = first;
        this.second = second;
    }

    public static <A extends Comparable<? super A>,
                    B extends Comparable<? super B>>
            Pair<A, B> of(A first, B second) {
        return new Pair<A, B>(first, second);
    }

    @Override
    public int compareTo(Pair<A, B> o) {
        int cmp = o == null ? 1 : (this.first).compareTo(o.first);
        return cmp == 0 ? (this.second).compareTo(o.second) : cmp;
    }

    @Override
    public int hashCode() {
        return 31 * hashcode(first) + hashcode(second);
    }

    // TODO : move this to a helper class.
    private static int hashcode(Object o) {
        return o == null ? 0 : o.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Pair))
            return false;
        if (this == obj)
            return true;
        return equal(first, ((Pair<?, ?>) obj).first)
                && equal(second, ((Pair<?, ?>) obj).second);
    }

    // TODO : move this to a helper class.
    private boolean equal(Object o1, Object o2) {
        return o1 == o2 || (o1 != null && o1.equals(o2));
    }

    @Override
    public String toString() {
        return "(" + first + ", " + second + ')';
    }
}

추가 / 수정 사항은 매우 환영합니다. :) 특히 사용에 대해 잘 모르겠습니다 Pair<?, ?>.

이 구문이 왜 필요한지에 대한 자세한 내용 은 객체가 Comparable을 구현하는지 확인 하고 자세한 설명 은 Java에서 일반 함수 를 구현하는 방법을 참조 하십시오 .max(Comparable a, Comparable b)


Java 정수가 32 비트이므로 첫 번째 해시 코드에 31을 곱하지 않으면 오버플로가 발생합니까? 독점적 인 OR을 수행하는 것이 낫지 않습니까?

@
Dan

5

내 의견으로는 Java에 Pair가 없습니다. 왜냐하면 쌍에 직접 추가 기능을 추가하려면 (예 : Comparable) 유형을 바인딩해야하기 때문입니다. C ++에서는 신경 쓰지 않으며 쌍을 구성하는 유형 operator <pair::operator <가 없으면 컴파일되지 않습니다.

경계가없는 Comparable의 예 :

public class Pair<F, S> implements Comparable<Pair<? extends F, ? extends S>> {
    public final F first;
    public final S second;
    /* ... */
    public int compareTo(Pair<? extends F, ? extends S> that) {
        int cf = compare(first, that.first);
        return cf == 0 ? compare(second, that.second) : cf;
    }
    //Why null is decided to be less than everything?
    private static int compare(Object l, Object r) {
        if (l == null) {
            return r == null ? 0 : -1;
        } else {
            return r == null ? 1 : ((Comparable) (l)).compareTo(r);
        }
    }
}

/* ... */

Pair<Thread, HashMap<String, Integer>> a = /* ... */;
Pair<Thread, HashMap<String, Integer>> b = /* ... */;
//Runtime error here instead of compile error!
System.out.println(a.compareTo(b));

형식 인수가 비교 가능한지 여부를 컴파일 타임과 비교 한 Comparable의 예는 다음과 같습니다.

public class Pair<
        F extends Comparable<? super F>, 
        S extends Comparable<? super S>
> implements Comparable<Pair<? extends F, ? extends S>> {
    public final F first;
    public final S second;
    /* ... */
    public int compareTo(Pair<? extends F, ? extends S> that) {
        int cf = compare(first, that.first);
        return cf == 0 ? compare(second, that.second) : cf;
    }
    //Why null is decided to be less than everything?
    private static <
            T extends Comparable<? super T>
    > int compare(T l, T r) {
        if (l == null) {
            return r == null ? 0 : -1;
        } else {
            return r == null ? 1 : l.compareTo(r);
        }
    }
}

/* ... */

//Will not compile because Thread is not Comparable<? super Thread>
Pair<Thread, HashMap<String, Integer>> a = /* ... */;
Pair<Thread, HashMap<String, Integer>> b = /* ... */;
System.out.println(a.compareTo(b));

이것은 좋지만 이번에는 비교할 수없는 유형을 쌍의 유형 인수로 사용할 수 없습니다. 일부 유틸리티 클래스에서는 쌍에 대해 많은 비교기를 사용할 수 있지만 C ++ 사람들은 그것을 얻지 못할 수 있습니다. 또 다른 방법은 유형 인수에 대해 다른 범위를 가진 유형 계층 구조에서 많은 클래스를 작성하는 것이지만 가능한 범위와 조합이 너무 많습니다.


5

JavaFX와 함께 제공되는 JavaFX에는 Pair <A, B> 클래스가 있습니다.


1
javafx.util.Pair의 해시 코드의 구현은 사소한 경우에 충돌이 발생할 수 있습니다. Java가 해시 코드뿐만 아니라 값의 동등성을 검사하기 때문에 HashMap / HashTable에서 사용하면 여전히 작동하지만 알고 있어야합니다.
sffc

그것은 매우 표준적이고 일반적으로 권장되는 hashCode 구현입니다. 호출 하는 모든 코드에서 충돌을 예상해야 합니다 hashCode(). Java 자체는이 메소드를 호출하지 않습니다. 라이브러리를 포함한 사용자 코드 용입니다.
AndrewF

5

다른 많은 사람들이 이미 언급했듯이 Pair 클래스가 유용한 지 여부는 실제로 유스 케이스에 달려 있습니다.

개인 도우미 기능의 경우 코드를 더 읽기 쉽게 만들고 모든 보일러 플레이트 코드로 또 다른 가치 클래스를 만들려는 노력이 없다면 Pair 클래스를 사용하는 것이 합법적이라고 생각합니다.

반면에 추상화 수준에서 두 객체 또는 값이 포함 된 클래스의 의미를 명확하게 문서화해야하는 경우 클래스를 작성해야합니다. 일반적으로 데이터가 비즈니스 오브젝트 인 경우입니다.

항상 그렇듯이 숙련 된 판단이 필요합니다.

두 번째 질문은 Apache Commons 라이브러리의 Pair 클래스를 권장합니다. Java 용 확장 표준 라이브러리로 간주 될 수 있습니다.

https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html

비즈니스 오브젝트의 값 클래스 작성을 단순화하는 Apache Commons의 EqualsBuilder , HashCodeBuilderToStringBuilder 를 살펴볼 수도 있습니다 .


업데이트 된 URL은 commons.apache.org/lang/api-release/index.html?org/apache/... 공유지 - lang3 베타 밖으로 때문이다. 이미 commons-lang 3을 사용하고 있다면 이것은 내 롬복 솔루션보다 훨씬 짧습니다.
Michael Piefel


5

좋은 소식 JavaFX 은 키 값 쌍을가집니다.

의존성으로 javafx를 추가하고 가져 오기 javafx.util.Pair ;

에서처럼 간단하게 사용하십시오 c++.

Pair <Key, Value> 

예 :

Pair <Integer, Integer> pr = new Pair<Integer, Integer>()

pr.get(key);// will return corresponding value

나쁜 소식은 모든 사람이 JavaFX를 사용하는 것은 아닙니다.
Michał Dobi Dobrzański



3

Java 언어의 본질에 따르면 사람들이 실제로을 필요로하지 않는다고 가정 Pair하고 인터페이스는 일반적으로 필요한 것입니다. 예를 들면 다음과 같습니다.

interface Pair<L, R> {
    public L getL();
    public R getR();
}

따라서 사람들이 두 개의 값을 반환하려면 다음을 수행하십시오.

... //Calcuate the return value
final Integer v1 = result1;
final String v2 = result2;
return new Pair<Integer, String>(){
    Integer getL(){ return v1; }
    String getR(){ return v2; }
}

이것은 매우 가벼운 솔루션이며 "의 의미는 무엇입니까 Pair<L,R>?"라는 질문에 대답합니다 . 답은 두 가지 유형이 다른 인터페이스 빌드이며 각 유형을 반환하는 메서드가 있다는 것입니다. 의미를 더 추가하는 것은 당신에게 달려 있습니다. 당신이 위치를 사용하고 정말 당신이 코드를 표시 할 경우 예를 들어, 정의 할 수 PositionXPositionY그 포함 Integer를 만들기 위해 Pair<PositionX,PositionY>. JSR 308이 사용 가능한 경우 Pair<@PositionX Integer, @PositionY Ingeger>이를 단순화하기 위해 사용할 수도 있습니다 .

편집 : 여기에 표시해야 할 한 가지는 위의 정의가 형식 매개 변수 이름과 메서드 이름과 명시 적으로 관련되어 있다는 것입니다. 이것은 Pair의미 정보가 부족하다는 주장에 대한 답변 입니다. 실제로이 방법 getL은 "유형 L 유형의 유형에 해당하는 요소를 제공합니다"를 의미합니다.

편집 : 다음은 삶을 더 쉽게 만들 수있는 간단한 유틸리티 클래스입니다.

class Pairs {
    static <L,R> Pair<L,R> makePair(final L l, final R r){
        return new Pair<L,R>(){
            public L getL() { return l; }
            public R getR() { return r; }   
        };
    }
}

용법:

return Pairs.makePair(new Integer(100), "123");

무엇에 대한 equals, hashCode그리고 toString?
sdgfsdh

글쎄, 이것은 최소한의 구현 일뿐입니다. 그 이상이 필요한 경우 좀 더 쉽게 돕기 위해 일부 도우미 함수를 작성할 수 있지만 여전히 코드를 작성해야합니다.
어스 엔진

구현하려면 toString두 필드 간의 관계에 대한 자세한 지식이 필요합니다.
어스 엔진

내 요점은 이러한 것들을 구현할 수 있기 때문에 class단순한 것보다 더 나은 것을 제공하는 interface것입니다.
sdgfsdh

3

구문 적으로 비슷하지만 Java와 C ++의 패러다임은 매우 다릅니다. Java와 같은 C ++를 작성하는 것은 나쁜 C ++이고 C ++과 같은 Java를 작성하는 것은 나쁜 Java입니다.

Eclipse와 같은 리플렉션 기반 IDE를 사용하면 "페어"클래스의 필수 기능을 작성하는 것이 빠르고 간단합니다. 클래스를 생성하고 두 개의 필드를 정의한 다음 다양한 "XX 생성"메뉴 옵션을 사용하여 몇 초 만에 클래스를 채 웁니다. Comparable 인터페이스를 원한다면 "compareTo"를 빠르게 입력해야 할 수도 있습니다.

언어에서 별도의 선언 / 정의 옵션을 사용하면 C ++ 코드 생성기가 그리 좋지 않으므로 작은 유틸리티 클래스를 작성하는 데 시간이 많이 걸립니다. 이 쌍은 템플릿이기 때문에 사용하지 않는 함수에 대해 비용을 지불 할 필요가 없으며 typedef 기능을 사용하면 의미있는 유형 이름을 코드에 할당 할 수 있으므로 "의미론 없음"에 대한 이의 제기가 실제로 보류되지 않습니다.


2

쌍은 복잡한 제네릭의 기본 구성 단위가되는 좋은 물건입니다. 예를 들어, 이것은 내 코드에서 온 것입니다.

WeakHashMap<Pair<String, String>, String> map = ...

Haskell 's Tuple과 동일


1
이제 Pair <A, B>를 사용하면 코드에 대한 정보가 적어지고 Pair를 사용하는 대신 특수 객체를 구현하는 것이 훨씬 좋습니다.
Illarion Kovalchuk

1
더 좋든 더 나쁘 든. 두 개의 인수 (예 : 그래프를 하나로 병합)를 결합하는 함수가 있고이를 캐시해야한다고 상상해보십시오. 여기에, Pair특별한 의미가 없습니다로 최적입니다. 명확한 개념의 명확한 이름을 갖는 것은 좋지만 "첫 번째"와 "두 번째"가 잘 작동하지 않는 이름을 찾는 것이 좋습니다.
maaartinus 님이

2

간단한 방법 Object []-치수 튜플로 사용 가능


2
어떤 차원이든 가능합니다. 그러나 : 번거롭고 형식이 안전하지 않습니다.
Michael Piefel

2

Java와 같은 프로그래밍 언어의 경우 대부분의 프로그래머가 쌍과 유사한 데이터 구조를 나타내는 데 사용하는 대체 데이터 구조는 두 개의 배열이며 동일한 색인을 통해 데이터에 액세스합니다.

예 : http://www-igm.univ-mlv.fr/~lecroq/string/node8.html#SECTION0080

이것은 데이터가 서로 묶여 있어야하기 때문에 이상적이지는 않지만 상당히 저렴합니다. 또한 사용 사례에 좌표 저장이 필요한 경우 자체 데이터 구조를 구축하는 것이 좋습니다.

나는 나의 도서관에서 이와 같은 것을 가지고있다.

public class Pair<First,Second>{.. }


2

다음은 편의를 위해 여러 수준의 튜플이있는 라이브러리입니다.

  • JavaTuples . 1-10 학년의 튜플 만 있으면됩니다.
  • JavaSlang . 0-8 도의 튜플과 다른 많은 기능적 장점.
  • jOOλ . 0-16 도의 튜플 및 기타 기능적 장점. (면책 조항, 나는 유지 보수 회사에서 일합니다)
  • 기능성 Java . 0-8 도의 튜플과 다른 많은 기능적 장점.

다른 라이브러리는 적어도 Pair 튜플 .

특히, 공칭 타이핑이 아닌 많은 구조적 타이핑을 사용하는 함수형 프로그래밍의 맥락 에서 (허용 된 답변에서 옹호 된 ) 라이브러리와 튜플은 매우 편리합니다.



2

또 다른 간결한 롬복 구현

import lombok.Value;

@Value(staticConstructor = "of")
public class Pair<F, S> {
    private final F first;
    private final S second;
}

1

모든 Pair 구현이 두 값의 순서에 따라 속성 의미로 퍼져있는 것을 알았습니다. 한 쌍을 생각할 때 두 항목의 순서가 중요하지 않은 두 항목의 조합을 생각합니다. 다음 은 컬렉션에서 원하는 동작을 보장하기 위해 재정렬 hashCode및 비 정렬 쌍의 구현입니다 equals. 또한 복제 가능합니다.

/**
 * The class <code>Pair</code> models a container for two objects wherein the
 * object order is of no consequence for equality and hashing. An example of
 * using Pair would be as the return type for a method that needs to return two
 * related objects. Another good use is as entries in a Set or keys in a Map
 * when only the unordered combination of two objects is of interest.<p>
 * The term "object" as being a one of a Pair can be loosely interpreted. A
 * Pair may have one or two <code>null</code> entries as values. Both values
 * may also be the same object.<p>
 * Mind that the order of the type parameters T and U is of no importance. A
 * Pair&lt;T, U> can still return <code>true</code> for method <code>equals</code>
 * called with a Pair&lt;U, T> argument.<p>
 * Instances of this class are immutable, but the provided values might not be.
 * This means the consistency of equality checks and the hash code is only as
 * strong as that of the value types.<p>
 */
public class Pair<T, U> implements Cloneable {

    /**
     * One of the two values, for the declared type T.
     */
    private final T object1;
    /**
     * One of the two values, for the declared type U.
     */
    private final U object2;
    private final boolean object1Null;
    private final boolean object2Null;
    private final boolean dualNull;

    /**
     * Constructs a new <code>Pair&lt;T, U&gt;</code> with T object1 and U object2 as
     * its values. The order of the arguments is of no consequence. One or both of
     * the values may be <code>null</code> and both values may be the same object.
     *
     * @param object1 T to serve as one value.
     * @param object2 U to serve as the other value.
     */
    public Pair(T object1, U object2) {

        this.object1 = object1;
        this.object2 = object2;
        object1Null = object1 == null;
        object2Null = object2 == null;
        dualNull = object1Null && object2Null;

    }

    /**
     * Gets the value of this Pair provided as the first argument in the constructor.
     *
     * @return a value of this Pair.
     */
    public T getObject1() {

        return object1;

    }

    /**
     * Gets the value of this Pair provided as the second argument in the constructor.
     *
     * @return a value of this Pair.
     */
    public U getObject2() {

        return object2;

    }

    /**
     * Returns a shallow copy of this Pair. The returned Pair is a new instance
     * created with the same values as this Pair. The values themselves are not
     * cloned.
     *
     * @return a clone of this Pair.
     */
    @Override
    public Pair<T, U> clone() {

        return new Pair<T, U>(object1, object2);

    }

    /**
     * Indicates whether some other object is "equal" to this one.
     * This Pair is considered equal to the object if and only if
     * <ul>
     * <li>the Object argument is not null,
     * <li>the Object argument has a runtime type Pair or a subclass,
     * </ul>
     * AND
     * <ul>
     * <li>the Object argument refers to this pair
     * <li>OR this pair's values are both null and the other pair's values are both null
     * <li>OR this pair has one null value and the other pair has one null value and
     * the remaining non-null values of both pairs are equal
     * <li>OR both pairs have no null values and have value tuples &lt;v1, v2> of
     * this pair and &lt;o1, o2> of the other pair so that at least one of the
     * following statements is true:
     * <ul>
     * <li>v1 equals o1 and v2 equals o2
     * <li>v1 equals o2 and v2 equals o1
     * </ul>
     * </ul>
     * In any other case (such as when this pair has two null parts but the other
     * only one) this method returns false.<p>
     * The type parameters that were used for the other pair are of no importance.
     * A Pair&lt;T, U> can return <code>true</code> for equality testing with
     * a Pair&lt;T, V> even if V is neither a super- nor subtype of U, should
     * the the value equality checks be positive or the U and V type values
     * are both <code>null</code>. Type erasure for parameter types at compile
     * time means that type checks are delegated to calls of the <code>equals</code>
     * methods on the values themselves.
     *
     * @param obj the reference object with which to compare.
     * @return true if the object is a Pair equal to this one.
     */
    @Override
    public boolean equals(Object obj) {

        if(obj == null)
            return false;

        if(this == obj)
            return true;

        if(!(obj instanceof Pair<?, ?>))
            return false;

        final Pair<?, ?> otherPair = (Pair<?, ?>)obj;

        if(dualNull)
            return otherPair.dualNull;

        //After this we're sure at least one part in this is not null

        if(otherPair.dualNull)
            return false;

        //After this we're sure at least one part in obj is not null

        if(object1Null) {
            if(otherPair.object1Null) //Yes: this and other both have non-null part2
                return object2.equals(otherPair.object2);
            else if(otherPair.object2Null) //Yes: this has non-null part2, other has non-null part1
                return object2.equals(otherPair.object1);
            else //Remaining case: other has no non-null parts
                return false;
        } else if(object2Null) {
            if(otherPair.object2Null) //Yes: this and other both have non-null part1
                return object1.equals(otherPair.object1);
            else if(otherPair.object1Null) //Yes: this has non-null part1, other has non-null part2
                return object1.equals(otherPair.object2);
            else //Remaining case: other has no non-null parts
                return false;
        } else {
            //Transitive and symmetric requirements of equals will make sure
            //checking the following cases are sufficient
            if(object1.equals(otherPair.object1))
                return object2.equals(otherPair.object2);
            else if(object1.equals(otherPair.object2))
                return object2.equals(otherPair.object1);
            else
                return false;
        }

    }

    /**
     * Returns a hash code value for the pair. This is calculated as the sum
     * of the hash codes for the two values, wherein a value that is <code>null</code>
     * contributes 0 to the sum. This implementation adheres to the contract for
     * <code>hashCode()</code> as specified for <code>Object()</code>. The returned
     * value hash code consistently remain the same for multiple invocations
     * during an execution of a Java application, unless at least one of the pair
     * values has its hash code changed. That would imply information used for 
     * equals in the changed value(s) has also changed, which would carry that
     * change onto this class' <code>equals</code> implementation.
     *
     * @return a hash code for this Pair.
     */
    @Override
    public int hashCode() {

        int hashCode = object1Null ? 0 : object1.hashCode();
        hashCode += (object2Null ? 0 : object2.hashCode());
        return hashCode;

    }

}

이 구현은 단위 테스트를 거쳤으며 세트 및 맵에서의 사용을 시도했습니다.

공개 도메인에서 이것을 공개한다고 주장하지 않습니다. 이것은 응용 프로그램에서 사용하기 위해 방금 작성한 코드이므로 사용하려는 경우 주석과 이름으로 약간의 직접 복사 및 엉망을 피하십시오. 드리프트 잡기?


3
실제로, 각 페이지의 하단을 확인하십시오 : "cc-wiki로 라이센스가 부여 된 사용자 기여"
amara

아, 나는 그것을 알아 차리지 못했다. 헤드 업 주셔서 감사합니다. 이 경우 해당 라이센스에 맞는 코드를 사용하십시오.
G_H

1
문제는 C ++ 동등한 쌍에 관한 것입니다. 또한 한 쌍의 객체에 대한 참조가 있고 컬렉션에 쌍을 삽입하는 것이 변경 가능한 한 정의되지 않은 동작이 발생할 수 있다고 생각합니다.
Mr_and_Mrs_D


1

com.sun.tools.javac.util.Pair는 한 쌍의 간단한 구현입니다. jdk1.7.0_51 \ lib \ tools.jar에 있습니다.

org.apache.commons.lang3.tuple.Pair 이외의 인터페이스는 단순한 인터페이스가 아닙니다.


2
그러나 아무도 JDK 내부 API를 사용해서는 안됩니다.
jpangamarca

0
public class Pair<K, V> {

    private final K element0;
    private final V element1;

    public static <K, V> Pair<K, V> createPair(K key, V value) {
        return new Pair<K, V>(key, value);
    }

    public Pair(K element0, V element1) {
        this.element0 = element0;
        this.element1 = element1;
    }

    public K getElement0() {
        return element0;
    }

    public V getElement1() {
        return element1;
    }

}

사용법 :

Pair<Integer, String> pair = Pair.createPair(1, "test");
pair.getElement0();
pair.getElement1();

불변, 한 쌍만!


오 와우. 다른 것? 좀 더 복잡한 제네릭과 함께 사용해보십시오. 언젠가는 적절한 유형을 유추하지 못합니다. 또한 다음이 가능해야합니다. Pair<Object, Object> pair = Pair.createPair("abc", "def")하지만 Pair.createPair((Object)"abc", (Object)"def")코드 로 작성 해야한다고 생각 합니까?
Quit--Anony-Mousse가

정적 메소드를 다음과 같이 바꿀 수 있습니다. @SuppressWarnings("unchecked") public static <K, V, X, Y> Pair<X, Y> createPair(K key, V value) { return new Pair<X, Y>((X) key, (Y) value); } 그러나 이것이 좋은 습관인지는 모르겠습니다
Bastiflew

아니, 아마도 더 많은 것을 망칠 것입니다. 내 경험상 적어도 하나의 컴파일러 (java6, java7, javadoc 및 eclipse java 컴파일러 시도)가 불평합니다. new Pair<Object, Object>("abc", "def")내 실험에서 가장 전통적 이었습니다.
종료-익명-무스
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.