tuple - pair of pair java




Qual è l'equivalente della coppia C++<L, R> in Java? (20)

C'è una buona ragione per cui non ci sono Pair<L,R> in Java? Quale sarebbe l'equivalente di questo costrutto C ++? Preferisco evitare di reimplementare il mio.

Sembra che 1.6 stia fornendo qualcosa di simile ( AbstractMap.SimpleEntry<K,V> ), ma sembra piuttosto contorto.



Android fornisce la classe Pair ( http://developer.android.com/reference/android/util/Pair.html ), qui l'implementazione:

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


Buona notizia Java aggiunto valore chiave Coppia.

importa semplicemente javafx.util.Pair ;

e usa semplicemente come in c++ .

Pair < Key , Value > 

per esempio

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

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

Classe di coppia compatibile con 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;
    }
}

Come molti altri hanno già affermato, dipende molto dal caso d'uso se una classe Pair è utile o meno.

Penso che per una funzione di helper privata sia del tutto legittimo usare una classe Pair se questo rende il tuo codice più leggibile e non vale la pena di creare un'altra classe di valore con tutto il suo codice di piastra.

D'altra parte, se il tuo livello di astrazione ti richiede di documentare chiaramente la semantica della classe che contiene due oggetti o valori, dovresti scrivere una classe per questo. Solitamente questo è il caso se i dati sono un oggetto aziendale.

Come sempre, richiede un giudizio competente.

Per la tua seconda domanda ti consiglio la classe Pair dalle librerie di Apache Commons. Quelli potrebbero essere considerati come librerie standard estese per Java:

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

Potresti anche dare un'occhiata ad EqualsBuilder , HashCodeBuilder e ToStringBuilder Apache Commons che semplificano la scrittura di classi di valore per i tuoi oggetti di business.


Ecco alcune librerie con più gradi di tuple per comodità:

  • JavaTuples . Le tuple del grado 1-10 sono tutto ciò che ha.
  • JavaSlang . Tuple dal grado 0-8 e molte altre chicche funzionali.
  • jOOλ . Tuple dal grado 0-16 e alcune altre chicche funzionali. (Disclaimer, lavoro per la società di manutenzione)
  • Java funzionale . Tuple dal grado 0-8 e molte altre chicche funzionali.

Altre librerie sono state menzionate per contenere almeno la Pair tupla.

Nello specifico, nel contesto della programmazione funzionale che utilizza un sacco di tipizzazione strutturale, piuttosto che una digitazione nominale ( come richiesto nella risposta accettata ), quelle librerie e le loro tuple sono molto utili.


Ho notato che tutte le implementazioni di coppia sparse qui attribuiscono il significato all'ordine dei due valori. Quando penso a una coppia, penso a una combinazione di due elementi in cui l'ordine dei due non ha importanza. Ecco la mia implementazione di una coppia non ordinata, con hashCode e hashCode per garantire il comportamento desiderato nelle raccolte. Anche clonabile.

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

    }

}

Questa implementazione è stata testata correttamente e l'uso in Set e Map è stato provato.

Si noti che non sto sostenendo di rilasciare questo nel pubblico dominio. Questo è il codice che ho appena scritto per l'uso in un'applicazione, quindi se lo si utilizzerà, si prega di astenersi dal fare una copia diretta e fare confusione con i commenti e i nomi un po '. Prendi la mia direzione?


In una discussione su comp.lang.java.help , Hunter Gratzner fornisce alcuni argomenti contro la presenza di un costrutto Pair in Java. L'argomento principale è che una Pair classi non trasmette alcuna semantica sulla relazione tra i due valori (come fai a sapere cosa significano "primo" e "secondo"?).

Una pratica migliore è scrivere una classe molto semplice, come quella proposta da Mike, per ogni applicazione che avresti fatto della classe Pair . Map.Entry è un esempio di coppia che ha il suo significato nel suo nome.

Per riassumere, secondo me è meglio avere una Position(x,y) classe Position(x,y) , una classe Range(begin,end) e una classe Entry(key,value) piuttosto che una Pair(first,second) generica Pair(first,second) che doesn Non dirmi nulla su cosa dovrebbe fare.


JavaFX (che viene fornito in bundle con Java 8) ha la classe Pair <A, B>


La coppia sarebbe una buona roba, per essere un'unità di costruzione di base per un generico complesso, ad esempio, questo è dal mio codice:

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

È proprio come la tupla di Haskell


Modo semplice Object [] - può essere utilizzato come una tupla di dimensioni diverse


Per i linguaggi di programmazione come Java, la struttura dati alternativa utilizzata dalla maggior parte dei programmatori per rappresentare coppie come le strutture dati sono due array e i dati sono accessibili tramite lo stesso indice

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

Questo non è l'ideale in quanto i dati dovrebbero essere legati insieme, ma risultano anche piuttosto economici. Inoltre, se il tuo caso d'uso richiede di memorizzare le coordinate, è meglio costruire la tua struttura dati.

Ho qualcosa di simile nella mia biblioteca

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

Puoi utilizzare la libreria AutoValue di Google: https://github.com/google/auto/tree/master/value .

Crei una classe astratta molto piccola e la annoti con @AutoValue e il processore di annotazione genera una classe concreta per te che ha un valore semantico.


Secondo la natura del linguaggio Java, suppongo che le persone non richiedano effettivamente una Pair , di solito un'interfaccia è ciò di cui hanno bisogno. Ecco un esempio:

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

Quindi, quando le persone vogliono restituire due valori, possono fare quanto segue:

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

Questa è una soluzione piuttosto leggera e risponde alla domanda "Qual è la semantica di una Pair<L,R> ?". La risposta è, questa è un'interfaccia build con due tipi (può essere diverso), e ha metodi per restituire ognuno di essi. Spetta a te aggiungere ulteriore semantica ad esso. Ad esempio, se stai usando Position e REALMENTE vuoi indicarlo nel tuo codice, puoi definire PositionX e PositionY che contengono Integer , per creare una Pair<PositionX,PositionY> . Se JSR 308 è disponibile, è possibile utilizzare anche Pair<@PositionX Integer, @PositionY Ingeger> per semplificarlo.

EDIT: Una cosa che dovrei indicare qui è che la definizione di cui sopra fa esplicitamente riferimento al nome del parametro type e al nome del metodo. Questa è una risposta a coloro che sostengono che una Pair è priva di informazioni semantiche. In realtà, il metodo getL significa "dammi l'elemento che corrisponde al tipo di parametro tipo L", che significa qualcosa.

EDIT: Ecco una semplice classe di utilità che può semplificare la vita:

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

utilizzo:

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

Secondo me, non c'è coppia in Java perché, se vuoi aggiungere funzionalità extra direttamente sulla coppia (es. Comparabile), devi associare i tipi. In C ++, non ci interessa, e se i tipi che compongono una coppia non hanno l' operator < , anche la pair::operator < non verrà compilata.

Un esempio di Paragonabile senza limiti:

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

Un esempio di Paragonabile con il controllo in fase di compilazione per verificare se gli argomenti di tipo sono comparabili:

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

Questo è buono, ma questa volta non puoi usare tipi non comparabili come argomenti tipo in Pair. Uno può usare molti Comparators for Pair in qualche classe di utilità, ma le persone C ++ potrebbero non averlo capito. Un altro modo è scrivere molte classi in una gerarchia di tipi con diversi limiti sugli argomenti di tipo, ma ci sono troppi limiti possibili e le loro combinazioni ...


Map.Entry interfaccia Map.Entry molto simile alla coppia c ++. Guarda l'implementazione concreta, come AbstractMap.SimpleEntry e AbstractMap.SimpleImmutableEntry Il primo elemento è getKey () e il secondo è getValue ().


Molte persone pubblicano il Paircodice che è utilizzabile come chiave in una mappa ... Se stai cercando di usare una coppia come chiave di hashing (un idioma comune), assicurati di controllare Guava Table<R,C,V>: http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table . Forniscono il seguente esempio di utilizzo, per i bordi del grafico:

Table<Vertex, Vertex, Double> weightedGraph = HashBasedTable.create();
weightedGraph.put(v1, v2, 4);
weightedGraph.put(v1, v3, 20);
weightedGraph.put(v2, v3, 5);

weightedGraph.row(v1); // returns a Map mapping v2 to 4, v3 to 20
weightedGraph.column(v3); // returns a Map mapping v1 to 20, v2 to 5

Una Tablemappa due chiavi per un singolo valore e fornisce anche ricerche efficienti per entrambi i tipi di chiavi. Ho iniziato a utilizzare questa struttura dati anziché una Map<Pair<K1,K2>, V>in molte parti del mio codice. Esistono array, alberi e altre implementazioni per usi densi e sparsi, con la possibilità di specificare le proprie classi di carte intermedie.


com.sun.tools.javac.util.Pair è una semplice implementazione di una coppia. Può essere trovato in jdk1.7.0_51 \ lib \ tools.jar.

Oltre a org.apache.commons.lang3.tuple.Pair, non è solo un'interfaccia.


Collections.singletonMap(left, rigth);




pair