programar programacion online mas lenguajes ideone ejemplos ejecutar demandados convertidor compiladores codigo java tuples pair

programacion - ¿Cuál es el equivalente del par de C++<L, R> en Java?



lenguajes de programacion mas demandados 2018 (30)

¿Hay alguna buena razón para que no haya un Pair<L,R> en Java? ¿Cuál sería el equivalente de esta construcción C ++? Preferiría evitar reimplementar la mía.

Parece que 1.6 está proporcionando algo similar ( AbstractMap.SimpleEntry<K,V> ), pero esto parece bastante complicado.


¿Qué tal http://www.javatuples.org/index.html Lo he encontrado muy útil.

Los javatuples te ofrecen clases de tuplas de uno a diez elementos:

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)


A pesar de ser sintácticamente similares, Java y C ++ tienen paradigmas muy diferentes. Escribir C ++ como Java es malo C ++, y escribir Java como C ++ es malo Java.

Con un IDE basado en la reflexión como Eclipse, escribir la funcionalidad necesaria de una clase de "par" es rápido y simple. Cree una clase, defina dos campos, use las distintas opciones de menú "Generar XX" para completar la clase en cuestión de segundos. Tal vez tendría que escribir un "compareTo" muy rápido si quisiera la interfaz comparable.

Con las opciones de declaración / definición separadas en el lenguaje, los generadores de códigos C ++ no son tan buenos, por lo que escribir a mano pocas clases de utilidad consume más tiempo. Debido a que el par es una plantilla, no tiene que pagar por las funciones que no usa, y la función typedef permite asignar nombres de letra significativos al código, por lo que las objeciones sobre "no semántica" realmente no se mantienen.


Android proporciona la clase Pair ( http://developer.android.com/reference/android/util/Pair.html ), aquí la implementación:

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



Aquí hay algunas bibliotecas que tienen varios grados de tuplas para su conveniencia:

  • JavaTuples . Tuples de grado 1-10 es todo lo que tiene.
  • JavaSlang . Tuplas de grado 0-8 y muchas otras golosinas funcionales.
  • jOOλ . Tuplas de grado 0-16 y algunas otras golosinas funcionales. (Descargo de responsabilidad, trabajo para la empresa mantenedora)
  • Java funcional . Tuplas de grado 0-8 y muchas otras golosinas funcionales.

Se ha mencionado que otras bibliotecas contienen al menos la tupla de Pair .

Específicamente, en el contexto de la programación funcional que utiliza una gran cantidad de tipificación estructural, en lugar de tipificación nominal ( como se recomienda en la respuesta aceptada ), estas bibliotecas y sus tuplas son muy útiles.



Buenas noticias Java agregado valor clave par.

solo importa javafx.util.Pair ;

y usar simplemente como en c++ .

Pair < Key , Value >

p.ej

Pair < Integer , Integer > pr = new Pair<Integer , Integer>() pr.get(key); // will return corresponding value


Clase de par compatible 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; } }


Como muchos otros ya han dicho, realmente depende del caso de uso si una clase Pair es útil o no.

Creo que para una función auxiliar privada es totalmente legítimo usar una clase de Par si eso hace que su código sea más legible y no vale la pena el esfuerzo de crear otra clase de valor con todo el código de la placa de la caldera.

Por otro lado, si su nivel de abstracción requiere que documente claramente la semántica de la clase que contiene dos objetos o valores, entonces debe escribir una clase para ello. Por lo general, ese es el caso si los datos son un objeto de negocio.

Como siempre, se requiere un juicio experto.

Para su segunda pregunta, recomiendo la clase Pair de las bibliotecas de Apache Commons. Esos podrían considerarse como bibliotecas estándar extendidas para Java:

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

También es posible que desee echar un vistazo a EqualsBuilder , HashCodeBuilder y ToStringBuilder Apache Commons, que simplifican la escritura de clases de valor para sus objetos comerciales.


De acuerdo con la naturaleza del lenguaje Java, supongo que la gente en realidad no requiere un Pair , una interfaz suele ser lo que necesitan. Aquí hay un ejemplo:

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

Entonces, cuando las personas desean devolver dos valores, pueden hacer lo siguiente:

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

Esta es una solución bastante liviana y responde a la pregunta "¿Cuál es la semántica de un Pair<L,R> ?". La respuesta es que se trata de una compilación de interfaz con dos tipos (puede ser diferente) y tiene métodos para devolver cada uno de ellos. Depende de usted agregarle más semántica. Por ejemplo, si está utilizando Posición y REALMENTE desea indicarlo en su código, puede definir PositionX y PositionY que contienen Integer , para formar un Pair<PositionX,PositionY> . Si JSR 308 está disponible, también puede usar Pair<@PositionX Integer, @PositionY Ingeger> para simplificarlo.

EDITAR: Una cosa que debería indicar aquí es que la definición anterior se relaciona explícitamente con el nombre del parámetro de tipo y el nombre del método. Esta es una respuesta a los argumentos que sostienen que un Pair es la falta de información semántica. En realidad, el método getL significa "dame el elemento que corresponde al tipo de tipo de parámetro L", que significa algo.

EDITAR: Aquí hay una clase de utilidad simple que puede hacer la vida más fácil:

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

uso:

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


Depende de para qué lo quieras usar. La razón típica para hacerlo es iterar sobre los mapas, para los que simplemente hace esto (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()); }


El mayor problema probablemente es que no se puede garantizar la inmutabilidad en A y B (consulte Cómo asegurarse de que los parámetros de tipo son inmutables ), por lo que hashCode() puede dar resultados inconsistentes para el mismo par después de que se inserte en una colección (por ejemplo dar un comportamiento indefinido, ver Definir iguales en términos de campos mutables ). Para una clase de par particular (no genérica), el programador puede asegurar la inmutabilidad eligiendo cuidadosamente A y B para ser inmutable.

De todos modos, borrando las advertencias genéricas de la respuesta de @ PeterLawrey (java 1.7):

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

Adiciones / correcciones muy bienvenidas :) En particular, no estoy muy seguro de mi uso del Pair<?, ?> .

Para obtener más información sobre por qué esta sintaxis, consulte Asegurarse de que los objetos implementan Comparable y para obtener una explicación detallada ¿Cómo implementar una función genérica max(Comparable a, Comparable b) en Java?


El par más corto que podría encontrar es el siguiente, utilizando Lombok :

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

Tiene todos los beneficios de la respuesta de @arturh (excepto la comparabilidad), tiene hashCode , equals , toString y un "constructor" estático.


En un hilo en comp.lang.java.help , Hunter Gratzner da algunos argumentos en contra de la presencia de una construcción Pair en Java. El argumento principal es que un Pair clase no transmite ninguna semántica sobre la relación entre los dos valores (¿cómo saber qué significan "primero" y "segundo"?).

Una práctica mejor es escribir una clase muy simple, como la que Mike propuso, para cada aplicación que hubieras hecho de la clase Pair . Map.Entry es un ejemplo de un par que lleva su significado en su nombre.

En resumen, en mi opinión, es mejor tener una Position(x,y) clase Position(x,y) , un Range(begin,end) clase Range(begin,end) y una Entry(key,value) clase Entry(key,value) lugar de un Pair(first,second) genérico Pair(first,second) que no No me digas nada de lo que se supone que haga.


En mi opinión, no hay Par en Java porque, si desea agregar funcionalidad adicional directamente en el par (por ejemplo, Comparable), debe vincular los tipos. En C ++, simplemente no nos importa, y si los tipos que componen un par no tienen el operator < , el pair::operator < no se compilará también.

Un ejemplo de Comparable sin límite:

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 ejemplo de comparación con la verificación en tiempo de compilación para ver si los argumentos de tipo son comparables:

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

Esto es bueno, pero esta vez puede que no use tipos no comparables como argumentos de tipo en Pair. Uno puede usar muchos Comparadores para emparejar en alguna clase de utilidad, pero las personas de C ++ pueden no obtenerlo. Otra forma es escribir muchas clases en una jerarquía de tipos con diferentes límites en los argumentos de tipo, pero hay demasiados límites posibles y sus combinaciones ...


Esto es Java. Tienes que crear tu propia clase de par a medida con nombres de clase y campo descriptivos, y no te preocupes si reinventas la rueda escribiendo hashCode () / equals () o implementando Comparable una y otra vez.


Interfaz Map.Entry muy cerca de c ++ par. Observe la implementación concreta, como AbstractMap.SimpleEntry y AbstractMap.SimpleImmutableEntry. El primer elemento es getKey () y el segundo es getValue ().


JavaFX (que viene incluido con Java 8) tiene la clase Pair <A, B>


Manera simple Objeto [] - puede usarse como cualquier tupla de dimensión


Noté que todas las implementaciones de Par están esparcidas por aquí, lo que significa un significado para el orden de los dos valores. Cuando pienso en un par, pienso en una combinación de dos elementos en los que el orden de los dos no tiene importancia. Aquí está mi implementación de un par desordenado, con hashCode y equals anulaciones para asegurar el comportamiento deseado en las colecciones. También clonado.

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

Esta implementación ha sido debidamente probada por unidades y se ha probado el uso en un Set and Map.

Tenga en cuenta que no pretendo liberar esto en el dominio público. Este es el código que acabo de escribir para su uso en una aplicación, por lo que si lo va a utilizar, evite hacer una copia directa y meterse un poco con los comentarios y nombres. ¿Me entiendes?


Otra forma de implementar Pair con.

  • Campos públicos inmutables, es decir, estructura de datos simple.
  • Comparable.
  • Hash simple e igual.
  • Fábrica simple para que no tenga que proporcionar los tipos. por ejemplo, Pair.of ("hola", 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 + '')''; } }


Par sería una buena cosa, ser una unidad de construcción básica para genéricos complejos, por ejemplo, esto es de mi código:

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

Es igual que la tupla de Haskell.


Para lenguajes de programación como Java, la estructura de datos alternativa utilizada por la mayoría de los programadores para representar pares como estructuras de datos son dos matrices, y se accede a los datos a través del mismo índice

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

Esto no es ideal ya que los datos deben estar unidos, pero también resultan ser bastante baratos. Además, si su caso de uso exige el almacenamiento de coordenadas, es mejor construir su propia estructura de datos.

Tengo algo como esto en mi biblioteca

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



Puede utilizar la biblioteca de AutoValue de Google: https://github.com/google/auto/tree/master/value .

Crea una clase abstracta muy pequeña y la anota con @AutoValue y el procesador de anotaciones genera una clase concreta para usted que tiene un valor semántico.


Muchas personas están publicando un Paircódigo que se puede usar como una clave en un Mapa ... Si está tratando de usar un par como una clave de hashing (un lenguaje común), asegúrese de consultar Guava Table<R,C,V>: http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table . Dan el siguiente uso de ejemplo, para bordes de gráficos:

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

A Tableasigna dos claves a un solo valor y también proporciona búsquedas eficientes para ambos tipos de claves. He comenzado a usar esta estructura de datos en lugar de una Map<Pair<K1,K2>, V>en muchas partes de mi código. Hay arreglos, árbol y otras implementaciones para usos densos y dispersos, con la opción de especificar sus propias clases de mapas intermedios.



com.sun.tools.javac.util.Pair es una implementación simple de un par. Se puede encontrar en jdk1.7.0_51 / lib / tools.jar.

Aparte de org.apache.commons.lang3.tuple.Pair, no es solo una interfaz.


Collections.singletonMap(left, rigth);


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

uso:

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

Inmutable, solo un par!