Java的值对集合?(元组?)

A Java collection of value pairs? (tuples?)

我喜欢Java有一个地图,你可以在地图中定义每个条目的类型,例如EDCOX1×0。

我要查找的是一种集合类型,其中集合中的每个元素都是一对值。对中的每个值都可以有自己的类型(如上面的字符串和整数示例),这是在声明时定义的。

集合将保持其给定的顺序,并且不会将其中一个值视为唯一键(如在映射中)。

本质上,我希望能够定义一个类型为或任何其他2个类型的数组。

我意识到我可以创建一个只包含两个变量的类,但这似乎过于冗长。

我也意识到我可以使用二维数组,但是由于我需要使用的类型不同,我必须使它们成为对象数组,然后我必须一直进行强制转换。

我只需要在集合中存储对,所以每个条目只需要两个值。像这样的东西不走上课路线就存在吗?谢谢!


抽象地图.simpleEntry

很简单,您正在寻找:

1
java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();

你怎么填?

1
2
3
4
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);

这简化为:

1
2
3
4
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方法,可以进一步将冗长性降低到:

1
2
pairList.add(createEntry("Not Unique key1", 1));
pairList.add(createEntry("Not Unique key2", 2));

由于ArrayList不是最终的,因此可以将其子类化,以公开of方法(以及前面提到的createEntry方法),从而使语法简洁:

1
2
3
TupleList<java.util.Map.Entry<String,Integer>> pair = new TupleList<>();
pair.of("Not Unique key1", 1);
pair.of("Not Unique key2", 2);


pair类是那些"gimme"泛型示例之一,这些示例很容易自己编写。例如,在我的头顶上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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());
  }

}

是的,这存在于网络上的多个地方,具有不同程度的完整性和特性。(我上面的例子是不可变的。)


Java 9 +

在Java 9中,可以简单地编写:EDCOX1,0,创建不可变对。

注意:此方法不允许键或值为空。例如,如果您想允许空值,您可以将其更改为:Map.entry(key, Optional.ofNullable(value))

Java 8 +

在Java 8中,可以使用更通用的EDCOX1(2)来创建一个不可变的、可串行化的对。此类不允许空键和空值。(在Java 9中,这个类包含在EDCOX1 3)模块中。编辑:对于Java 11,JavaFX已经与JDK脱钩,因此您需要额外的Maven工件org .OpenJFX:JavaFX Basic。

Java 6 +

在Java 6和UP中,对于一个值可以改变的对,可以使用更冗长的EDCOX1(4)对不可变的一对,或者EDCOX1×5Ω。这些类还允许空键和空值,并且是可序列化的。

安卓

如果您是为Android编写,只需使用Pair.create(key, value)创建一个不变的对。

阿帕奇公地

Apache Commons Lang提供了有用的Pair.of(key, value)来创建一个不变的、可比较的、可序列化的对。

Eclipse集合

如果您使用的是包含原语的对,那么Eclipse集合将提供一些非常有效的原语对类,以避免所有效率低下的自动装箱和自动拆箱。

例如,可以使用PrimitiveTuples.pair(int, int)创建IntIntPair,或者使用PrimitiveTuples.pair(float, long)创建FloatLongPair

龙目岛计划

使用Project Lombok,只需编写以下内容,就可以创建不可变的对类:

1
2
3
4
5
@Value
public class Pair<K, V> {
    K key;
    V value;
}

Lombok将在生成的字节码中自动为您填写constructor、getters、equals()hashCode()toString()方法。如果您想要一个静态工厂方法而不是一个构造函数,例如Pair.of(k, v),只需将注释更改为:@Value(staticConstructor ="of")

否则

如果上面的所有解决方案都没有使您的船浮起,您可以简单地复制和粘贴以下代码(与接受的答案中列出的类不同,这可以防止nullpointerExceptions):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;
    }
}


Map.Entry

这些内置类也是一个选项。两者都实现了Map.Entry接口。

  • AbstractMap.SimpleEntry
  • AbstractMap.SimpleImmutableEntry

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


APACHE通用Lang3有两个类,在这个线程中提到的其他几个库,与Java中的C++对l、R>等价的是什么?

符合原始问题要求的示例:

1
2
3
4
5
6
7
8
9
10
11
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());
}


对于任何为Android开发的人,您都可以使用android.util.pair。:)


"ApacheCommonsLang3"的Pair类和相关的子类怎么样?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    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坐标,如果需要的话。

1
2
3
4
5
        <dependency>
            <groupId>org.apache.commons</groupId>
            commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>

您可以编写一个泛型对类,并在数组或列表中使用它。是的,您必须编写一个类,但是您可以为所有类型重用同一个类,因此您只需要编写一次。


我想问你是不是不想只用一个List>?但是,当然,JDK没有Pair<>类。但一个快速的谷歌在维基百科和forums.sun.com上都找到了一个。干杯


如您所描述的,首选的解决方案是一组对(即列表)。

为了实现这一点,您将创建一个在集合中使用的Pair类。这是一个有用的实用程序类,可以添加到代码库中。

SunJDK中最接近的类,提供类似于典型的Pair类的功能,是AbstractMap.SimpleEntry。你可以使用这个类,而不是创建你自己的配对类,尽管你必须忍受一些尴尬的限制,我认为大多数人会对这一点表示不满,因为它不是SimpleEntry的预期角色。例如,simpleEntry没有"setkey()"方法,也没有默认的构造函数,因此您可能会发现它太有限。

请记住,集合的设计目的是包含单个类型的元素。相关的实用程序接口(如map)实际上不是集合(即map不实现集合接口)。一对组合也不会实现收集接口,但在构建更大的数据结构中显然是一个有用的类。


扩展其他答案时,一般不可变对应该具有静态方法,以避免将代码与对构造函数的调用混淆在一起:

1
2
3
4
5
6
7
8
9
10
11
12
13
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",那么代码将变得流畅,因为您可以编写:

1
2
    list.add(Pair.of(x,y)); // my preference
    list.add(pairOf(x,y)); // use with import static x.y.Pair.pairOf

这是一个真正的耻辱,核心Java库是如此稀少,这样的事情,你必须使用共用的朗朗或其他第三方来做这样的基本东西。还有另一个升级到scala的原因…


这是基于javahelp4u的代码。

不那么冗长,并且显示如何在一行中进行操作以及如何循环操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//======>  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());
}

创建一个类

1
2
3
4
5
class tuples
{
int x;
int y;
}

然后创建这个元组对象的列表

1
List<tuples> list = new ArrayList<tuples>();

因此,您也可以用相同的方式实现其他新的数据结构。


ApacheCrunch还有一个Pair类:http://crunch.apache.org/apidocs/0.5.0/org/apache/crunch/pair.html


我的意思是,即使Java中没有EDCOX1的18个类,也有相当的SimMalar:EDCOX1,21

地图录入文件

这(简化了很多)是HashMap或实际上任何Map存储的。

您可以创建一个EDOCX1的实例(23),将您的值存储在其中并获取条目集。你最终会得到一个Set>,这实际上是你想要的。

所以:

1
2
3
4
5
6
7
8
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
}


在项目反应器(IO.项目反应器:反应器芯)中,有对n-tuples的高级支持:

1
Tuple2<String, Integer> t = Tuples.of("string", 1)

在这里,您可以得到t.getT1(), t.getT2(), ...,特别是使用流或通量,您甚至可以映射tuple元素:

1
2
Stream<Tuple2<String, Integer>> s;
s.map(t -> t.mapT2(i -> i + 2));


那com.sun.tools.javac.util.pair呢?


在谈到键/值对时,我首先想到的是属性类,在该类中,可以将项保存并加载到流/文件中。