19

I am new to Java, I want to store an array of pair of doubles. My code looks like this:

import java.util.ArrayList;
import java.util.Map.Entry;

List<Entry<Double, Double>> values = new ArrayList<>();
Entry<Double, Double> pair;
// set pair values:
// pair.setKey(0.5); // this method does not exists
// pair.setValue(3.6);
values.add(pair);

How can I initialize the pair variable? Is there a better structure to store my array of pair of doubles?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Benjamin Crouzier
  • 40,265
  • 44
  • 171
  • 236

10 Answers10

18

Create your own class to represent a pair and add a constructor that takes two arguments:

public class MyPair
{
    private final Double key;
    private final Double value;

    public MyPair(Double aKey, Double aValue)
    {
        key   = aKey;
        value = aValue;
    }

    public Double key()   { return key; }
    public Double value() { return value; }
}

See this answer for reasons why a Pair does not exist in Java: What is the equivalent of the C++ Pair<L,R> in Java?

Community
  • 1
  • 1
hmjd
  • 120,187
  • 20
  • 207
  • 252
  • 2
    I am surprised there is not something that I can use in the standard java library for such a simple thing – Benjamin Crouzier Mar 05 '12 at 14:41
  • 4
    See this answer for reasons why no such `Pair` exists: http://stackoverflow.com/questions/156275/what-is-the-equivalent-of-the-c-pairl-r-in-java – hmjd Mar 05 '12 at 14:42
  • note that this solution increases project complexity greatly as you might have 100 different classes that are effectively pairs, but each has distinct type; requiring custom marshalling between the types, which is both error prone, looks ugly, and expensive(as you can't blit from one to another, and cache hostility). Its ok if all pairlikes implemented their own marshallers, this solves all problems except performance and different versions of pair having differently named base interface, which can be solved by not having an interface and using reflection, but now you have other problems. – Dmytro Apr 03 '17 at 20:23
7

You don't want to use Entry it's an INTERFACE, not a CLASS. That interface is used by an implementations of Set when you call entrySet() on a class that implements Map. It basically lets you manipulate the implemented Map as though it were a Set.

What you would do (but can't) is this. If you try to do this you'll see a compiler error along the lines of "Cannot instantiate the type Map.Entry". That's because Map.Entry is an interface, not a class. An interface doesn't contain any real code, so there's no real constructor to run here.

Entry<Double, Double> pair = new Entry<Double, Double>();

If you look at the below docs you can clearly see at the top that it's a "Interface Map.Entry" which means it's an interface. http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Map.Entry.html

What you should do instead of trying to instantiate an interface, which is impossible, is create your own class called Pair. Something like this. Remember to change the package if you use the below code.

package org.mike.test;

public class Pair {
    private double x = 0.0;
    private double y = 0.0;

    public Pair(double x, double y)
    {
        this.x = x;
        this.y = y;
    }

    public Pair()
    {

    }

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }


}

After writing your Pair class your code will now look like this.

package org.mike.test;

import java.util.ArrayList;
import org.mike.test.Pair; //You don't need this if the Pair class is in the same package as the class using it

public class tester {

    /**
     * @param args
     */
    public static void main(String[] args) {
        ArrayList<Pair> values = new ArrayList<Pair>();
        Pair pair = new Pair();
        // set pair values:
        pair.setY(3.6);
        pair.setX(3.6);
        values.add(pair);
    }

}
Jazzepi
  • 5,259
  • 11
  • 55
  • 81
  • Nice, and give that you gave us a Pair(double, double) constructor, I'd simplify and remove the setX/Y() calls and use Pair pair = new Pair(3.6, 3.6); – Leif Jul 15 '16 at 06:47
2

Couldn't you just use

public class MyClass<A,B> extends ArrayList{
private A first;
private B second;
public MyClass(A first, B second){
super();
this.first = first;
this.second = second;}
}

and then add some form of add method, along with a first and second accessor & mutator method? I'm sort of new to programming, but this way would seem like it might work, and be accessible to things other than just the DOUBLE, (in case down the road you want to use other types, like Integer, or even String).

Xanthian23
  • 55
  • 9
1

You could use a map to solve this.

FrediWeber
  • 1,099
  • 1
  • 10
  • 21
1

Is Entry a class you defined? You instantiate it with new.

Entry<Double, Double> pair = new Entry<Double, Double>(d1, d2);

Note I am assuming you defined a constructor that takes 2 doubles, and you have references for d1 and d2.

I suggest you NOT use the Map.Entry class. The semantics for that class are such that the values are a key and a value, fitting with the way Maps work.

hvgotcodes
  • 118,147
  • 33
  • 203
  • 236
0

For someone into competitive programming or coding interview questions you may have a requirement to write all the code in a single file/editor window

in that case, you may use inner classes to conveniently make a pair and then use an object of that class as a pair

if you want to create a stack of Pairs you can create a Pair object and put it in the stack

import java.util.*;
public class PairArray
{
    static class Pair{
        int a,b;
        Pair(int a,int b){
            this.a=a;
            this.b=b;
        }
    }
    static void main()
    {
        int a,b,l=10;
        Scanner sc = new Scanner(System.in);
        Pair array[]= new Pair[l];
        for(int i=0;i<l;i++){
           a=sc.nextInt();
           b=sc.nextInt();
           array[i]=new Pair(a,b);
        }
        for(int i=0;i<l;i++){
           System.out.println(array[i].a+" "+array[i].b);
        }

    }
}
Omnicacorp
  • 41
  • 7
0

Please find below program which gives count of pairs available in array.

int getPairsCount(int n, int[] arr) {

    HashMap<Integer, Integer> hm = new HashMap<>();

    for (int i = 0; i < arr.length; i++) {
        if (hm.containsKey(arr[i])) {
            hm.replace(arr[i], hm.get(arr[i]) + 1);
        } else {
            hm.put(arr[i], 1);
        }
    }

    int sum = 0;
    for (Map.Entry<Integer, Integer> hmm : hm.entrySet()) {
        if (hmm.getValue() / 2 > 0) {
            sum += (hmm.getValue() / 2);
        }
    }
    return sum;
}
Sushant Poman
  • 375
  • 2
  • 9
0

The Map.Entry type that you are trying to use is just an interface, and can therefore not be instantiated. If you wanted to (mis)use internal types of Map, then the concrete Map.Entry implementation HashEntry would be an option.

It is however a much better idea to implement you own Pair type. Or to use a Map instead of an array if that suits you needs.

rompetroll
  • 4,781
  • 2
  • 37
  • 50
0

Another approach, and probably the most efficient way to store and array of double pairs is to use a single array of doubles, and use (2*i) and (2*i + 1) as your indexing scheme. Additionally you gain the advantage that the array will be initialized to all 0s when you create it, no additional steps required. Unfortunately there is a little extra coding overhead to implement add() and remove(), but surprisingly, it's probably less than creating your own container class for the pair.

class MyClass {
    double[] values;
    int count;

    MyClass(int initialCapacity) {
        values = new double[initialCapacity*2];
    }

    // adding a pair
    void addPair(double x, double y) {
        if (count*2 >= values.length) {
            values = Arrays.copyOf(values, values.length*2);
        }
        values[count*2] = x;
        values[count*2 + 1] = y;
        count++;
    }

    void remove(int index) {
        if (index >= count) throw new IndexOutOfBoundsException();

        if (index < --count) {
            System.arraycopy(values, (index+1)*2, values, index*2, (count - index) * 2);
        }
    }

    int size() { return count; }

    // both these should check that index < count.
    double getX(int index) { return values[index*2]; }
    double getY(int index) { return values[index*2 + 1]; }

    void exampleIteration() {
        // getX/Y accessors are examples of how to get
        // the values, but it will be more efficient
        // in most cases to just access the array
        // array directly as so...
        for (int i=0 ; i<count ; ++i) {
            System.out.printf("%d: (%f,%f)%n", i, values[i*2], values[i*2+1]);
        }
    }
}
ɲeuroburɳ
  • 6,990
  • 3
  • 24
  • 22
-1

If you have access to Entry class, you could create a constructor that takes key and value as parameters.

Entry<Double, Double> pair = new Entry<Double, Double>(0.5, 3.6);
values.add(pair);
John Eipe
  • 10,922
  • 24
  • 72
  • 114