Java'da C ++ Pair <L, R> eşdeğeri nedir?


671

Pair<L,R>Java'da yok olmasının iyi bir nedeni var mı? Bu C ++ yapısının eşdeğeri ne olurdu? Kendimi yeniden uygulamaktan kaçınmayı tercih ederim.

1.6 benzer bir şey sağlıyor gibi görünüyor ( AbstractMap.SimpleEntry<K,V>), ama bu oldukça kıvrık görünüyor.


7
Neden AbstractMap.SimpleEntrykıvrık?
CurtainDog

27
Namig nedeniyle, bir anahtarı ve bir değeri rastgele adlandırmak.
Enerccio


2
@sffc JavaFX, JDK7'deki varsayılan sınıfyollarının hiçbirinde bulunmaz, bu nedenle JFX çalışma zamanı kitaplıklarının el ile eklenmesini gerektirir.
Kordon Rehn

3
@Enerccio: Yani, "anahtar" ve "değer" - ise "ilk" ve "ikinci" nin keyfi olmadığını söylüyorsunuz? O zaman bu SDK'da böyle bir sınıfın olmamasının iyi bir nedenidir. "Doğru" adlandırma konusunda sonsuz bir anlaşmazlık olacaktır.
fdreger

Yanıtlar:


400

Gelen bir iplikcomp.lang.java.help , Hunter Gratzner bir varlığı karşı bazı argümanları verir PairJava yapı. Temel argüman, bir sınıfın Pairiki değer arasındaki ilişki hakkında herhangi bir anlambilim içermemesidir ("birinci" ve "ikinci" nin ne anlama geldiğini nasıl bilebilirsiniz?).

Daha iyi bir uygulama, Mike'ın önerdiği gibi, sınıftan yapacağınız her uygulama için çok basit bir sınıf yazmaktır Pair. Map.Entryanlamında taşıyan bir çift örneğidir.

Özetle, bana göre ne yapması gerektiği hakkında bir şey söylemeyen bir jenerikten ziyade bir sınıf Position(x,y), bir sınıf Range(begin,end)ve bir sınıfa sahip olmak Entry(key,value)daha iyidir Pair(first,second).


143
Gratzner saçları ayırıyor. İlkel veya yerleşik bir sınıf olarak tek bir değeri bir sınıfa kapsüllemeden döndürmekten mutluluk duyuyoruz. Bir düzine öğeden oluşan bir demet döndürecek olsaydık, hiç kimse kendi sınıfına sahip olması gerektiğini kabul etmeyecekti. Ortada bir yerde (bulanık) bir bölme çizgisidir. Kertenkele beyinlerimizin çiftlerle kolayca başa çıkabileceğini düşünüyorum.
Ian

25
Ian'a katılıyorum. Java int döndürmenize izin verir; sizi her kullanışınızda int için bir takma ad oluşturmaya zorlamaz. Çiftler çok farklı değil.
Clément

5
Bir çifti doğrudan yerel değişkenlerinize açabilirsek veya iki bağımsız değişkeni alan bir yönteme iletebilirsek, Pair yararlı bir sınıf olacaktır. Bunu böyle açamadığımız için, anlamlı bir sınıf yaratmak ve değerleri bir arada tutmak çok kötü görünmüyor. Ve, sınırlamalara rağmen gerçekten bir çift istiyorsanız, her zaman Object [2] + atma :-) vardır
marcus

Mesele şu ki, Gratzner'a katılmıyorsanız, çeşitli yerlerde Çifti uygulamaları var. Apache Commons ve Guava'da IIRC var. Bunları kullanın. Ancak, ana Java kütüphanelerine bir şey koymak, bunun (Yapma) Asil ve Onaylanmış Bir İş Yapma Yolu olduğu anlamına gelir (kapitalizasyon ile) ve insanlar buna katılmadığı için, onu oraya koymamalıyız. Eski kütlelerde olduğu gibi yeterince sarsıntı var, gereksiz yere daha fazla koymayalım.
Haakon Løtveit

1
@Dragas Ben bir çift değer gerekiyorsa o zaman Java değil ... ciddi?
idclev 463035818

156

Bu Java. Kendi tanımlanmış Pair sınıfınızı tanımlayıcı sınıf ve alan adlarıyla yapmanız gerekir ve hashCode () / equals () yazarak veya tekrar tekrar Karşılaştırılabilir uygulayarak tekerleği yeniden icat edeceğinizi aklınızdan çıkarmayın.


61
Bu "neden" sorusuna cevap vermiyor. ('Bu bir java' cevabı olarak düşünmüyorsanız)
Nikita Rybak

127
Java'nın ayrıntılarını alay etmek için +1. Aslında soruyu cevaplamadığım için -1.
Bennett McElwee

19
Eğer bir Pair sınıfı içeren Apache Commong Lang'i işaret etseydiniz, Java-alay konusu iyi olurdu.
haylem

6
Veya sadece kullanabilirsinizSimpleImmutableEntry
CurtainDog

33
İlk cümle "neden?" Sorusunu cevaplar. Bu Java ve hepsi bu.
masterziv

103

HashMap uyumlu Çift sınıfı:

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
Muhtemelen ayarlayıcıları silmek ve birinci ve ikinci final yapmak, böylece çifti değişmez hale getirmek istiyorsunuz. (Birisi bir karma anahtarı olarak kullandıktan sonra bileşenleri değiştirirse, garip şeyler olur).
Thilo

21
toString () yönteminde "(" + first.toString () + "," + second.toString () + ")" döndürmek NullPointerExceptions atabilir. Bu daha iyi: dönüş "(" + ilk + "," + saniye + ")";
Juha Syrjälä

6
Ayrıca, çifti "son" olarak işaretleyin veya ilk eşittir satırını 'if (other! = Null && this.getClass () == other.getClass ())' olarak değiştirin
'11

8
Rastgele nooby sorusu için özür dilerim, ama neden yapıcıda super () çağrınız var?
İbrahim

6
@Ibrahim: Bu durumda, gereksiz --- dışarı çıkardıysanız davranış tamamen aynıdır super(). Normalde, isteğe bağlıysa, burada olduğu gibi onu silmeyi tercih ederim.
Chris Jester-Young

53

Gelebileceğim en kısa çift Lombok'u kullanarak :

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

Bu tüm faydaları vardır @arturh gelen cevap sahip olduğu, (karşılaştırılabilmesi hariç) hashCode, equals, toStringve statik “kurucu”.


Şık! Beğendim!
Ahmet Ipkin


31

Pair ile uygulamanın başka bir yolu.

  • Kamusal değişmez alanlar, yani basit veri yapısı.
  • Karşılaştırılabilir.
  • Basit karma ve eşittir.
  • Basit fabrika, böylece türleri sağlamak zorunda değilsiniz. örn. ("merhaba", 1) çifti;

    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
Statik fabrika yöntemini seviyorum of. Google Guava'nın değişmez koleksiyonlarını hatırlatıyor .
Jarek Przygódzki

7
Sen döküm noktada olduğu o1için Comparablehiçbir şey aslında o arabirimini uygulayacak göstermesine rağmen,. Bu bir gereklilikse, FIRSTtype parametresi olmalıdır FIRST extends Comparable<?>.
G_H

Ben bir java adamı değilim, bu yüzden lütfen cehaletim için beni affet, ama TODO yorumlarında ne tür bir yardımcı sınıf düşünüyordun?

3
31 hashCode için kötü bir sabittir. Örneğin, 2B harita için Eşleştir <Tamsayı, Tamsayı> ile anahtarlanan HashMap kullanırsanız, birçok çarpışma gerçekleşir. Örneğin (a * 65497) ^ b daha uygun olacaktır.
Michał Zieliński

1
@MarioCarneiro ^ xor, güç değil
Michał Zieliński

27

Http://www.javatuples.org/index.html Nasıl çok faydalı buldum.

Javatuples size bir ila on eleman arasında tuple sınıfları sunar:

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
Komik, ama kullanmayı hayal edebileceğimden en az 5 ders daha var.
maaartinus

3
@maaartinus Kullanacağımdan en az 10 daha fazla.
Boann

7
@Boann: Tamam, düzeltilmeye devam ediyorum. Eskiden kullanıyordum Pairve Tripletbelki de her 50 yılda bir kullanmayı hayal edebiliyordum . Şimdi Lombok kullanıyorum ve her bir çifte ihtiyacım olduğunda küçük bir 4 satırlık sınıf oluşturuyorum. Yani "10 çok fazla" doğrudur.
maaartinus

5
Bir Bottom (0 element)sınıfa ihtiyacımız var mı? :)
Dünya Motoru

2
Vay canına bu çirkin. Açık bir şekilde yapmaya çalıştıklarını biliyorum, ama C # gibi aşırı yüklenmiş paramitlere sahip bir Tuple daha güzel olurdu.
arviman

12

Ne için kullanmak istediğinize bağlıdır. Bunu yapmanın tipik nedeni, sadece bunu yaptığınız haritalar üzerinde yineleme yapmaktır (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
Özel bir sınıfın bu durumda yardımcı olacağından emin değilim :)
Nikita Rybak

31
"Bunun tipik nedeni, haritalar üzerinde yineleme yapmaktır". Gerçekten mi?
Bennett McElwee

12

android Pairsınıfı sağlar ( http://developer.android.com/reference/android/util/Pair.html ), burada uygulama:

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(..)Guava kütüphanesi gerektirir.
Markus L

3
Objects.equals(...)2011'den beri Java'da olanı değiştirin (1.7).
AndrewF

9

En büyük sorun muhtemelen A ve B'de değişmezliği garanti edememesidir (bkz . Tip parametrelerinin değişmez olduğundan nasıl emin olunur ), bu nedenle örneğin bir koleksiyona yerleştirildikten sonrahashCode() aynı Çifti için tutarsız sonuçlar verebilir (bu tanımsız davranış verecektir) Değişken alanları açısından eşitleri tanımlama konusuna bakın ). Belirli bir (jenerik olmayan) Pair sınıfı için programcı, A ve B'yi değiştirilemez olarak dikkatlice seçerek değişmezliği sağlayabilir.

Her neyse, jenerik uyarılarını @ PeterLawrey'in cevabından (java 1.7) siliyoruz:

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 + ')';
    }
}

Eklemeler / düzeltmeler çok hoş geldiniz :) Özellikle benim kullanım hakkında pek emin değilim Pair<?, ?>.

Neden bu sözdizimi hakkında daha fazla bilgi için bkz: Nesnelerin Karşılaştırılabilir uygulamalarını sağlama ve ayrıntılı bir açıklama için max(Comparable a, Comparable b)Java'da genel bir işlev nasıl uygulanır ?


Java Tamsayıları 32 bit olduğundan, ilk karma kodu 31 ile çarpmak taşma anlamına gelmez mi? Özel bir VEYA yapmak daha iyi olmaz mıydı?
Dan

@Dan düzenlemek çekinmeyin Ben java uzak taşındı :)
Mr_and_Mrs_D

5

Benim düşünceme göre, Java'da hiçbir Çifti yoktur, çünkü doğrudan çifte ekstra işlevsellik eklemek istiyorsanız (örn. Karşılaştırılabilir), türleri sınırlamanız gerekir. C ++ 'da sadece umursamıyoruz ve bir çifti oluşturan türler yoksa operator <, pair::operator <derlenmeyecektir.

Sınırlama olmadan karşılaştırılabilir bir örnek:

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));

Tür bağımsız değişkenlerinin karşılaştırılabilir olup olmadığına ilişkin derleme zamanı denetimi ile karşılaştırılabilir bir örnek:

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));

Bu iyidir, ancak bu kez Eşleştir'de tür bağımsız değişkenleri olarak karşılaştırılamaz türleri kullanamazsınız. Bazı yardımcı sınıflarda Pair için çok sayıda Karşılaştırıcı kullanılabilir, ancak C ++ kullanıcıları bunu alamayabilir. Başka bir yol, tür argümanlarında farklı sınırlara sahip bir tür hiyerarşisinde çok sayıda sınıf yazmaktır, ancak çok fazla olası sınır ve bunların kombinasyonları vardır ...


5

JavaFX (Java 8 ile birlikte gelir) Pair <A, B> sınıfına sahiptir


1
Javafx.util.Pair içinde hashCode uygulanması önemsiz durumlar üzerinde çarpışmaların yol açabilir. HashMap / HashTable'da kullanmak, Java karma kodlarına ek olarak değerlerin eşitliğini kontrol ettiğinden hala işe yarayacaktır, ancak farkında olunması gereken bir şeydir.
sffc

Bu çok standart ve yaygın olarak önerilen bir hashCode uygulamasıdır. Çarpışmalar çağıran herhangi bir kod tarafından beklenmelidir hashCode(). Java'nın kendisi bu yöntemi çağırmaz. Kütüphaneler dahil kullanıcı kodu içindir.
AndrewF

5

Diğerlerinin belirttiği gibi, bir Pair sınıfının yararlı olup olmadığı gerçekten kullanım durumuna bağlıdır.

Özel bir yardımcı işlevi için kodunuzu daha okunabilir hale getirir ve tüm kazan plaka kodu ile başka bir değer sınıfı oluşturma çabaya değmezse bir Pair sınıfı kullanmak tamamen meşru olduğunu düşünüyorum.

Öte yandan, soyutlama seviyeniz iki nesne veya değer içeren sınıfın anlambilimini açıkça belgelemenizi gerektiriyorsa, bunun için bir sınıf yazmalısınız. Genellikle veriler bir iş nesnesiyse böyle olur.

Her zaman olduğu gibi, yetenekli yargı gerektirir.

İkinci sorunuz için Apache Commons kütüphanelerinden Pair sınıfını öneriyorum. Bunlar Java için genişletilmiş standart kütüphaneler olarak düşünülebilir:

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

Ayrıca , iş nesneleriniz için değer sınıfları yazmayı basitleştiren Apache Commons'ın EqualsBuilder , HashCodeBuilder ve ToStringBuilder'e de göz atmak isteyebilirsiniz .


Güncellenmiş URL commons.apache.org/lang/api-release/index.html?org/apache/… şeklindedir, çünkü commons-lang3 beta sürümü dışındadır. Zaten commons-lang 3 kullanıyorsanız, bu benim kendi Lombok
çözümümden


5

İyi JavaFXHaber'in anahtar değeri vardır Çifti.

javafx'ı bağımlılık olarak ekleyin ve içe aktarın javafx.util.Pair;

ve olduğu gibi kullanın c++.

Pair <Key, Value> 

Örneğin

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

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

Kötü haber şu ki herkes JavaFX kullanmıyor
Michał Dobi Dobrzański



3

Java dilinin doğasına göre, insanların aslında bir Pairşeye ihtiyaç duymadığını düşünüyorum, bir arayüz genellikle ihtiyaç duydukları şeydir. İşte bir örnek:

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

İnsanlar iki değer döndürmek istediklerinde şunları yapabilirler:

... //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; }
}

Bu oldukça hafif bir çözüm ve "a'nın semantiği nedir Pair<L,R>?" Cevap, bu iki (farklı olabilir) tipte bir arayüz derlemesi ve her birini döndürmek için yöntemleri var. Daha fazla semantik eklemek size kalmıştır. Eğer Konumunu kullanarak ve gerçekten kodda bunu belirtmek istiyorum eğer Örneğin, Tanımlayabileceğiniz PositionXve PositionYbu içeren Integerbir telafi etmek, Pair<PositionX,PositionY>. JSR 308 mevcutsa, Pair<@PositionX Integer, @PositionY Ingeger>basitleştirmek için de kullanabilirsiniz .

EDIT: Burada belirtmek gerekir şey, yukarıdaki tanım açıkça type parametre adı ve yöntem adı ilişkilidir. Bu, a'nın Pairsemantik bilgi eksikliği olduğunu savunuyor . Aslında, yöntem getL"bana L parametresi türüne karşılık gelen öğeyi ver" anlamına gelir, bu da bir şey ifade eder.

EDIT: İşte hayatı kolaylaştıracak basit bir yardımcı sınıf:

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; }   
        };
    }
}

kullanımı:

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

Ne hakkında equals, hashCodeve toString?
sdgfsdh

bu sadece minimal bir uygulama. Bundan daha fazlasına ihtiyacınız varsa, kolaylaştırmak için bazı yardımcı işlevler yazabilirsiniz, ancak yine de kodu yazmanız gerekir.
Dünya Motoru

Uygulamak toStringiçin iki alan arasındaki ilişki hakkında daha fazla bilgiye ihtiyacınız var.
Earth Engine

Demek istediğim, bu şeyleri uygulayabileceğinden bir şeyden classdaha iyi interfaceolabilir.
sdgfsdh

3

Sözdizimsel olarak benzer olmasına rağmen, Java ve C ++ çok farklı paradigmalara sahiptir. Java gibi C ++ yazmak kötü C ++ ve Java gibi C ++ yazmak kötü Java'dır.

Eclipse gibi yansıma tabanlı bir IDE ile, mutlaka bir "pair" sınıfının işlevselliğini yazmak hızlı ve basittir. Sınıf oluşturun, iki alan tanımlayın, birkaç saniye içinde sınıfı doldurmak için çeşitli "Generate XX" menü seçeneklerini kullanın. Karşılaştırılabilir arabirimi istiyorsanız, belki de bir "CompareTo" gerçek hızlı yazmanız gerekir.

Dilde ayrı beyan / tanım seçenekleri ile C ++ kod üreteçleri o kadar iyi değil, bu yüzden el küçük yardımcı sınıflar yazmak daha zaman alıcı tedium. Çift bir şablon olduğundan, kullanmadığınız işlevler için ödeme yapmanız gerekmez ve typedef özelliği, koda anlamlı tür adları atamaya izin verir, bu nedenle "anlambilimsiz" ile ilgili itirazlar gerçekte kalmaz.


2

Çift, karmaşık bir jenerik için temel bir inşaat birimi olmak için iyi bir şey olurdu, örneğin, bu benim kodumdan:

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

Haskell'in Tuple'i ile aynı


1
Şimdi, <A, B> Pair kullanmanın kodu daha az bilgilendirici hale getirdiğini ve Pair yerine özel nesnelerin uygulanmasının çok daha iyi olduğunu söyleyebilirim
Illarion Kovalchuk

1
İyi ya da kötü. İki argümanı birleştiren bir işleve sahip olduğunuzu düşünün (örneğin, grafikleri birleştirme) ve önbelleğe almanız gerekir. Burada, Pairözel anlambilim olmadığından en uygunudur. Açık bir kavram için açık bir isme sahip olmak iyidir, ancak "birinci" ve "ikinci" nin iyi çalışmadığı bir isim aramak iyidir.
maaartinus

2

Basit bir şekilde Nesne [] - bir boyut kümesi olarak kullanılabilir


2
Herhangi bir boyut, evet. Ancak: Oluşturmak hantal ve tip güvenli değil.
Michael Piefel

2

Java gibi programlama dilleri için, çoğu programcı tarafından veri yapıları gibi çifti temsil etmek için kullanılan alternatif veri yapısı iki dizidir ve verilere aynı dizin üzerinden erişilir

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

Bu, verilerin birbirine bağlanması gerektiği için ideal değil, aynı zamanda oldukça ucuz olduğu ortaya çıktı. Ayrıca, kullanım durumunuz koordinatların saklanmasını gerektiriyorsa, kendi veri yapınızı oluşturmak daha iyidir.

Kütüphanemde böyle bir şey var

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

2

Google'ın AutoValue kütüphanesini kullanabilirsiniz - https://github.com/google/auto/tree/master/value .

Çok küçük bir soyut sınıf oluşturursunuz ve @AutoValue ile ek açıklama eklersiniz ve ek açıklama işlemcisi sizin için semantik değeri olan somut bir sınıf oluşturur.


2

Size kolaylık sağlamak için birkaç derece tuple içeren bazı kütüphaneler:

  • JavaTuples . 1-10 derece tuples sahip olduğu tek şey.
  • JavaSlang . 0-8 derece tuples ve diğer birçok fonksiyonel güzellik.
  • JOOλ . 0-16 derece tuples ve diğer bazı fonksiyonel hediyeler. (Sorumluluk reddi, ben bakım şirketi için çalışıyorum)
  • Fonksiyonel Java . 0-8 derece tuples ve diğer birçok fonksiyonel güzellik.

Diğer kütüphanelerin en azından Pairdemet içerdiği belirtilmiştir .

Özellikle, nominal yazımdan ( kabul edilen cevapta savunulan şekilde) ziyade çok sayıda yapısal yazımdan yararlanan fonksiyonel programlama bağlamında , bu kütüphaneler ve grupları çok kullanışlı olur.



2

başka bir kısa lombok uygulaması

import lombok.Value;

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

1

Burada etrafa serilmiş olan tüm Pair uygulamalarının iki değerin sırasına anlam atfettiğini fark ettim. Bir çifti düşündüğümde, ikisinin sırasının önemli olmadığı iki öğenin bir kombinasyonunu düşünüyorum. İşte koleksiyonlarda istenen davranışı sağlamak için sıralı olmayan bir çifti uyguladığım hashCodeve equalsgeçersiz kıldığım . Ayrıca klonlanabilir.

/**
 * 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;

    }

}

Bu uygulama düzgün bir şekilde birim test edilmiş ve bir Küme ve Haritadaki kullanım denenmiştir.

Bunu kamu malı olarak yayınladığımı iddia etmiyorum. Bu sadece bir uygulamada kullanmak için yazdığım kod, bu yüzden onu kullanacaksanız, lütfen doğrudan bir kopya yapmaktan ve yorum ve isimlerle biraz karışıklıktan kaçının. Driftimi yakaladın mı?


3
aslında, her sayfanın altını kontrol edin: "cc-wiki altında lisanslanan kullanıcı katkıları"
amara

Ah, bunu fark etmemiştim. Söylediğin için teşekkürler. Bu durumda, söz konusu lisans kapsamında uygun gördüğünüz şekilde kodu kullanın.
G_H

1
Soru, sipariş edilen bir C ++ eşdeğer çifti hakkındadır. Ayrıca bir çiftin nesnesi için bir başvuru olduğu ve bunların değişebilir ekleme koleksiyonlarda çiftleri tanımsız davranışa yol açabilir düşünüyorum.
Mr_and_Mrs_D


1

com.sun.tools.javac.util.Pair bir çiftin basit bir uygulamasıdır. Jdk1.7.0_51 \ lib \ tools.jar içinde bulunabilir.

Org.apache.commons.lang3.tuple.Pair dışında, bu sadece bir arayüz değildir.


2
Yine de hiç kimse JDK dahili API'lerini kullanmamalıdır.
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;
    }

}

kullanım:

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

Değişmez, sadece bir çift!


Vay canına. Bir diğeri? Sizinkini daha karmaşık Jenerikler ile kullanmayı deneyin - bir noktada uygun türleri çıkartamaz. Ayrıca, aşağıdakiler mümkün olmalıdır: Pair<Object, Object> pair = Pair.createPair("abc", "def")ama Pair.createPair((Object)"abc", (Object)"def")kodunuzla yazmak gerektiğini düşünüyorum ?
QUIT VAR - Anony-Mousse

statik yöntemi @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); } bununla değiştirebilirsiniz: ama iyi bir uygulama olup olmadığını bilmiyorum
Bastiflew

Hayır, bu sadece işleri daha da berbat edecektir. Deneyimlerime göre, derleyicilerden en az biri (java6, java7, javadoc ve eclipse java derleyicisini deneyin) şikayet edecektir. Geleneksel new Pair<Object, Object>("abc", "def")deneylerimde en güvenilir olanıydı.
QUIT - Anony-Mousse
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.