Java-коллекция пар ценностей? (кортежи?)
Мне нравится, как Java имеет карту, где вы можете определить типы каждой записи на карте, например <String, Integer>
.
То, что я ищу, - это тип коллекции, где каждый элемент в коллекции представляет собой пару значений. Каждое значение в паре может иметь свой собственный тип (например, пример String и Integer выше), который определяется во время объявления.
Коллекция сохранит свой заданный порядок и не будет рассматривать одно из значений как уникальный ключ (как на карте).
По сути, я хочу иметь возможность определять ARRAY типа <String,Integer>
или любые другие 2 типа.
Я понимаю, что я могу создать класс, в котором есть только две переменные, но это кажется слишком многословным.
Я также понимаю, что я мог бы использовать 2D-массив, но из-за разных типов, которые мне нужно использовать, мне пришлось бы создавать их массивы OBJECT, и тогда мне пришлось бы делать все время.
Мне нужно хранить пары в коллекции, поэтому мне нужно всего два значения для каждой записи. Что-то вроде этого существует, не пройдя маршрут класса? Спасибо!
Ответы
Ответ 1
Класс Pair является одним из тех примеров "gimme" generics, которые достаточно легко написать самостоятельно. Например, от верхней части головы:
public class Pair<L,R> {
private final L left;
private final R right;
public Pair(L left, R right) {
this.left = left;
this.right = right;
}
public L getLeft() { return left; }
public R getRight() { return right; }
@Override
public int hashCode() { return left.hashCode() ^ right.hashCode(); }
@Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) return false;
Pair pairo = (Pair) o;
return this.left.equals(pairo.getLeft()) &&
this.right.equals(pairo.getRight());
}
}
И да, это существует в нескольких местах в Сети с различной степенью полноты и функциональности. (Мой пример выше предназначен для неизменности.)
Ответ 2
Легко вы ищете:
java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();
Как вы можете его заполнить?
java.util.Map.Entry<String,Integer> pair1=new java.util.AbstractMap.SimpleEntry<>("Not Unique key1",1);
java.util.Map.Entry<String,Integer> pair2=new java.util.AbstractMap.SimpleEntry<>("Not Unique key2",2);
pairList.add(pair1);
pairList.add(pair2);
Это упрощает:
Entry<String,Integer> pair1=new SimpleEntry<>("Not Unique key1",1);
Entry<String,Integer> pair2=new SimpleEntry<>("Not Unique key2",2);
pairList.add(pair1);
pairList.add(pair2);
И, с помощью метода createEntry
, можно еще больше уменьшить многословие:
pairList.add(createEntry("Not Unique key1", 1));
pairList.add(createEntry("Not Unique key2", 2));
Так как ArrayList
не является окончательным, он может быть подклассифицирован, чтобы выставить метод of
(и вышеупомянутый метод createEntry
), в результате получив синтаксически краткое:
TupleList<java.util.Map.Entry<String,Integer>> pair = new TupleList<>();
pair.of("Not Unique key1", 1);
pair.of("Not Unique key2", 2);
Ответ 3
Ява 9+
В Java 9 вы можете просто написать: Map.entry(key, value)
чтобы создать неизменную пару.
Примечание: этот метод не позволяет ключам или значениям быть нулевыми. Например, если вы хотите разрешить нулевые значения, вы должны изменить это на: Map.entry(key, Optional.ofNullable(value))
.
Ява 8+
В Java 8 вы можете использовать более универсальный javafx.util.Pair
для создания неизменяемой, сериализуемой пары. Этот класс допускает нулевые ключи и нулевые значения. (В Java 9 этот класс включен в модуль javafx.base
). РЕДАКТИРОВАТЬ: Начиная с Java 11, JavaFX был отделен от JDK, поэтому вам потребуется дополнительный артефакт maven org.openjfx: javafx-base.
Ява 6+
В Java 6 и более поздних версиях вы можете использовать более подробный AbstractMap.SimpleImmutableEntry
для неизменной пары или AbstractMap.SimpleEntry
для пары, значение которой можно изменить. Эти классы также допускают нулевые ключи и нулевые значения и являются сериализуемыми.
Android
Если вы пишете для Android, просто используйте Pair.create(key, value)
чтобы создать неизменную пару.
Apache Commons
Apache Commons Lang
предоставляет полезную Pair.of(key, value)
для создания неизменяемой, сопоставимой, сериализуемой пары.
Коллекции Затмения
Если вы используете пары, которые содержат примитивы, Eclipse Collections предоставляет несколько очень эффективных классов примитивных пар, которые позволят избежать всех неэффективных автоматических и автоматических распаковок.
Например, вы можете использовать PrimitiveTuples.pair(int, int)
для создания IntIntPair
или PrimitiveTuples.pair(float, long)
для создания FloatLongPair
.
Проект Ломбок
Используя Project Lombok, вы можете создать неизменный класс пары просто написав:
@Value
public class Pair<K, V> {
K key;
V value;
}
Lombok автоматически заполнит для вас сгенерированный байт-код методы constructor, getters, equals()
, hashCode()
и toString()
. Если вам нужен статический метод фабрики вместо конструктора, например, Pair.of(k, v)
, просто измените аннотацию на: @Value(staticConstructor = "of")
.
Иначе
Если ни одно из вышеперечисленных решений не поддерживает вашу лодку, вы можете просто скопировать и вставить следующий код (который, в отличие от класса, указанного в принятом ответе, защищает от исключений NullPointerExceptions):
import java.util.Objects;
public class Pair<K, V> {
public final K key;
public final V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public boolean equals(Object o) {
return o instanceof Pair && Objects.equals(key, ((Pair<?,?>)o).key) && Objects.equals(value, ((Pair<?,?>)o).value);
}
public int hashCode() {
return 31 * Objects.hashCode(key) + Objects.hashCode(value);
}
public String toString() {
return key + "=" + value;
}
}
Ответ 4
Map.Entry
Эти встроенные классы тоже являются опцией. Оба реализуют интерфейс Map.Entry
.
![UML diagram of Map.Entry interface with pair of implementing classes]()
Ответ 5
Apache common lang3 имеет класс Pair и несколько других библиотек, упомянутых в этом потоке Что такое эквивалент С++ Pair < L, R > в Java?
Пример соответствия требованиям вашего исходного вопроса:
List<Pair<String, Integer>> myPairs = new ArrayList<Pair<String, Integer>>();
myPairs.add(Pair.of("val1", 11));
myPairs.add(Pair.of("val2", 17));
//...
for(Pair<String, Integer> pair : myPairs) {
//following two lines are equivalent... whichever is easier for you...
System.out.println(pair.getLeft() + ": " + pair.getRight());
System.out.println(pair.getKey() + ": " + pair.getValue());
}
Ответ 6
Для тех, кто разрабатывает Android, вы можете использовать android.util.Pair.:)
Ответ 7
Что относительно класса Apache Commons Lang 3 "Pair
и относительных подклассов?
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
...
@SuppressWarnings("unchecked")
Pair<String, Integer>[] arr = new ImmutablePair[]{
ImmutablePair.of("A", 1),
ImmutablePair.of("B", 2)};
// both access the 'left' part
String key = arr[0].getKey();
String left = arr[0].getLeft();
// both access the 'right' part
Integer value = arr[0].getValue();
Integer right = arr[0].getRight();
ImmutablePair
- это конкретный подкласс, который не позволяет изменять значения в паре, но существуют другие реализации с различной семантикой. Это координаты Maven, если они вам нужны.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
Ответ 8
Вы могли бы написать общий Pair < A, B > класса и использовать его в массиве или списке. Да, вам нужно написать класс, но вы можете повторно использовать один и тот же класс для всех типов, поэтому вам нужно сделать это только один раз.
Ответ 9
Я собирался спросить, не хотите ли вы просто использовать List<Pair<T, U>>
? но тогда, конечно, JDK не имеет класса Pair < > . Но быстрый Google нашел его на Wikipedia и forums.sun.com. Приветствия
Ответ 10
Предпочтительным решением, как вы описали, является список пар (т.е. список).
Для этого вы создадите класс Pair для использования в своей коллекции. Это полезный класс полезности для добавления в базу кода.
Самый близкий класс в Sun JDK, обеспечивающий функциональность, похожую на типичный класс Pair, - AbstractMap.SimpleEntry. Вы могли бы использовать этот класс, а не создавать свой собственный класс Pair, хотя вам придется жить с некоторыми неудобными ограничениями, и я думаю, что большинство людей будут на него нахмуриться, так как это не является на самом деле предполагаемой ролью SimpleEntry. Например, SimpleEntry не имеет метода setKey() и конструктора по умолчанию, поэтому вы можете считать его слишком ограниченным.
Имейте в виду, что коллекции предназначены для размещения элементов одного типа. Связанные служебные интерфейсы, такие как Map, фактически не являются коллекциями (т.е. Map не реализует интерфейс Collection). Пара не будет реализовывать интерфейс Collection, но, очевидно, является полезным классом при построении больших структур данных.
Ответ 11
Развернувшись на другом, общая универсальная пара должна иметь статический метод, чтобы избежать загромождения вашего кода вызовом конструктора:
class Pair<L,R> {
final L left;
final R right;
public Pair(L left, R right) {
this.left = left;
this.right = right;
}
static <L,R> Pair<L,R> of(L left, R right){
return new Pair<L,R>(left, right);
}
}
если вы назовете статический метод "of" или "pairOf", код станет свободным, так как вы можете написать:
list.add(Pair.of(x,y)); // my preference
list.add(pairOf(x,y)); // use with import static x.y.Pair.pairOf
его реальный позор, что основные java-библиотеки настолько разрежены в таких вещах, что вы должны использовать commons-lang или другие третьи стороны, чтобы делать такие базовые вещи. еще одна причина для обновления до scala...
Ответ 12
Это основано на коде JavaHelp4u.
Менее подробный и показывает, как делать в одной строке и как перебирать вещи.
//======> Imports
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
//======> Single Entry
SimpleEntry<String, String> myEntry = new SimpleEntry<String, String>("ID", "Text");
System.out.println("key: " + myEntry.getKey() + " value:" + myEntry.getValue());
System.out.println();
//======> List of Entries
List<Entry<String,String>> pairList = new ArrayList<>();
//-- Specify manually
Entry<String,String> firstButton = new SimpleEntry<String, String>("Red ", "Way out");
pairList.add(firstButton);
//-- one liner:
pairList.add(new SimpleEntry<String,String>("Gray", "Alternate route")); //Ananomous add.
//-- Iterate over Entry array:
for (Entry<String, String> entr : pairList) {
System.out.println("Button: " + entr.getKey() + " Label: " + entr.getValue());
}
Ответ 13
Apache Crunch также имеет класс Pair
:
http://crunch.apache.org/apidocs/0.5.0/org/apache/crunch/Pair.html
Ответ 14
просто создайте класс вроде
class tuples
{
int x;
int y;
}
затем создайте Список этих объектов кортежей
List<tuples> list = new ArrayList<tuples>();
чтобы вы могли также реализовать другие новые структуры данных таким же образом.
Ответ 15
Я имею в виду, хотя в Java нет класса Pair
, есть что-то довольно симпатичное: Map.Entry
Map.Entry Documentation
Это (немного упрощает) то, что HashMap
, или на самом деле хранится Map
.
Вы можете создать экземпляр Map
сохранить в нем свои значения и получить задание. В итоге вы получите Set<Map.Entry<K,V>>
, который вам действительно нужен.
Итак:
public static void main(String []args)
{
HashMap<String, Integer> values = new HashMap<String,Integer>();
values.put("A", 235);//your custom data, the types may be different
//more data insertions....
Set<Map.Entry<String,Integer>> list = values.entrySet();//your list
//do as you may with it
}
Ответ 16
Как насчет com.sun.tools.javac.util.Pair?
Ответ 17
Первая мысль, когда я говорю о парах ключ/значение, - это класс свойств, в котором вы можете сохранять и загружать элементы в поток/файл.
Ответ 18
В проекте Reactor (io.projectreactor: реактор-ядро) есть расширенная поддержка n-Tuples:
Tuple2<String, Integer> t = Tuples.of("string", 1)
Там вы можете получить t.getT1(), t.getT2(),...
Особенно с Stream или Flux вы даже можете отобразить элементы кортежа:
Stream<Tuple2<String, Integer>> s;
s.map(t -> t.mapT2(i -> i + 2));
Ответ 19
Хотя этот вопрос старый, посмотрите на vavr.io. Они обеспечивают неизменную реализацию Tuples, вплоть до Tuple8. https://www.vavr.io/vavr-docs/#_tuples
Ответ 20
Spring имеет Pair<S,T>
тип в пакете утилит данных org.springframework.data.util
Pair<String,Integer> pair = Pair.of("Test", 123);
System.out.println(pair.getFirst());
System.out.println(pair.getSecond());