Java коллекция пар значений? (кортежи?) - PullRequest
303 голосов
/ 06 февраля 2009

Мне нравится, как у Java есть Карта, где вы можете определить типы каждой записи на карте, например <String, Integer>.

То, что я ищу, - это тип коллекции, в которой каждый элемент коллекции представляет собой пару значений. Каждое значение в паре может иметь свой собственный тип (например, пример String и Integer выше), который определяется во время объявления.

Коллекция будет поддерживать свой заданный порядок и не будет рассматривать одно из значений как уникальный ключ (как на карте).

По сути, я хочу иметь возможность определить массив типа <String,Integer> или любые другие 2 типа.

Я понимаю, что могу создать класс только с двумя переменными, но это кажется слишком многословным.

Я также понимаю, что могу использовать 2D-массив, но из-за различных типов, которые мне нужно использовать, мне придется создавать их как массивы OBJECT, а затем мне придется все время приводить.

Мне нужно только хранить пары в коллекции, поэтому мне нужно только два значения для каждой записи. Существует ли что-то подобное без прохождения классового маршрута? Спасибо!

Ответы [ 18 ]

271 голосов
/ 29 июня 2012

AbstractMap.SimpleEntry

Легко, вы ищете это:

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);
233 голосов
/ 06 февраля 2009

Класс Pair является одним из тех обобщающих примеров типа gimme, который достаточно легко написать самостоятельно. Например, с макушки головы:

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

}

И да, это существует в разных местах сети, с различной степенью полноты и функциональности. (Мой пример выше должен быть неизменным.)

112 голосов
/ 02 сентября 2014

Java 9 +

В Java 9 вы можете просто написать: Map.entry(key, value) создать неизменную пару.

Примечание: этот метод не допускает, чтобы ключи или значения были нулевыми. Например, если вы хотите разрешить нулевые значения, вы можете изменить это на: Map.entry(key, Optional.ofNullable(value)).


Java 8 +

В Java 8 вы можете использовать более универсальный javafx.util.Pair для создания неизменяемой, сериализуемой пары. Этот класс позволяет разрешать нулевые ключи и нулевые значения. (В Java 9 этот класс включен в модуль javafx.base). РЕДАКТИРОВАТЬ: Начиная с Java 11, JavaFX был отделен от JDK, поэтому вам потребуется дополнительный артефакт maven org.openjfx: javafx-base.


Java 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 автоматически заполнит методы конструктора, геттера, equals(), hashCode() и toString() для вас в сгенерированном байт-коде. Если вам нужен статический метод фабрики вместо конструктора, например, Pair.of(k, v), просто измените аннотацию на: @Value(staticConstructor = "of").


В противном случае

Если ни одно из вышеперечисленных решений не всплыло на вашей лодке, вы можете просто скопировать и вставить следующий код (который, в отличие от класса, указанного в принятом ответе, защищает от исключений NullPointerException):

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;
    }
}
61 голосов
/ 06 февраля 2009

Map.Entry

Эти встроенные классы также являются опцией. Оба реализуют интерфейс Map.Entry.

UML diagram of Map.Entry interface with pair of implementing classes

30 голосов
/ 12 декабря 2012

Apache common lang3 имеет класс Pair и несколько других библиотек, упомянутых в этой теме Что является эквивалентом пары C ++ в 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());
}
18 голосов
/ 15 мая 2014

Любой, кто разрабатывает для Android, может использовать android.util.Pair . :)

15 голосов
/ 14 ноября 2015

А как насчет класса "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>
6 голосов
/ 06 февраля 2009

Я собирался спросить, не хотите ли вы просто использовать List<Pair<T, U>>? но тогда, конечно, JDK не имеет класса Pair <>. Но быстрый Google нашел его в Википедии и forums.sun.com . Приветствия

6 голосов
/ 06 февраля 2009

Предпочтительное решение, как вы его описали, - это список пар (т.е. список).

Для этого вы должны создать класс Pair для использования в вашей коллекции. Это полезный служебный класс для добавления в вашу базу кода.

Ближайший класс в Sun JDK, обеспечивающий функциональность, аналогичную типичному классу Pair, - это AbstractMap.SimpleEntry. Вы можете использовать этот класс, а не создавать свой собственный класс Pair, хотя вам придется жить с некоторыми неловкими ограничениями, и я думаю, что большинство людей не одобрит это как не совсем предназначенную роль SimpleEntry. Например, SimpleEntry не имеет метода setKey () и конструктора по умолчанию, поэтому вы можете счесть его слишком ограничивающим.

Имейте в виду, что коллекции предназначены для элементов одного типа. Связанные служебные интерфейсы, такие как Map, на самом деле не являются коллекциями (т. Е. Map не реализует интерфейс Collection). Пара также не реализует интерфейс Collection, но, очевидно, является полезным классом для построения больших структур данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...