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

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

Ответ 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;
    }
}

Ответ 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());
}

Ответ 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());