How do I store a set of paired numbers in java? Do I use lists or arrays or maybe something else?
eg. [ (1,1) , (2,1) , (3,5)]
There are a few options:
Write a custom IntPair class
class IntPair {
// Ideally, name the class after whatever you're actually using
// the int pairs *for.*
final int x;
final int y;
IntPair(int x, int y) {this.x=x;this.y=y;}
// depending on your use case, equals? hashCode? More methods?
}
and then create an IntPair[] or a List<IntPair>.
Alternately, create a two-dimensional array new int[n][2], and treat the rows as pairs.
Java doesn't have a built-in Pair class for a few reasons, but the most noticeable is that it's easy enough to write a class that has the same function, but has much more enlightening, helpful names for the class, its fields, and its methods.
If we knew more about what you're actually using this for, we might be able to provide more detailed suggestions -- for all we know, a Map could be appropriate here.
If you're using JavaFX, you can use the class Pair.
import javafx.util.Pair;
int x = 23;
int y = 98;
Pair<Integer, Integer> pair1 = new Pair<>(6, 7);
Pair <Integer, Integer> pair2 = new Pair<>(x, y);
Way 1 : Using javafx.util.Pair class
Pair<Integer> myPair1 = new Pair<Integer>(10,20);
Pair<Integer> myPair2 = new Pair<Integer>(30,40);
HashSet<Pair<Integer>> set = new HashSet<>(); // Java 8 and above
set.add(myPair1);
set.add(myPair2);
Way 2: Using int[] of size 2
int[] myPair1 = new int[] {10,20}; // myPair1[0]=10 , myPair[1] = 20
int[] myPair2 = new int[] {30,40};
HashSet<int[]> set = new HashSet<>(); // Java 8 and above
Way 3 : Converting pair into single number
int myPair1 = 10 * 1000 + 20;
// int first = myPair1 / 1000; second = myPair2 % 1000;
int myPair2 = 30 * 1000 + 40;
HashSet<Integer> set = new HashSet<>();
set.add(myPair1);
set.add(myPair2);
Way 4 : Using ArrayList instead of int[] in way 2
Way 5 : Custom class that uses HashSet and Pair internally
class Pair<T> {
T p1, p2;
Pair(T p1, T p2) {
this.p1 = p1;
this.p2 = p2;
}
Pair<Integer> pair = new Pair<Integer>(1,2);
int i1 = pair.p1;
int i2 = pair.p2;
You can also put in getters, setters, equals, hashcode, etc.
If you can live with low level structures and desperately need compact form of "literal" form of "set of pairs" -- this happens to me in unit test, when I need a set of fixtures -- you can simply use an array of arrays:
int[][] squares = {
{ 1, 1 },
{ 2, 4 },
{ 3, 9 }
};
But keep in mind that there is no semantic to such a type -- it all depends on proper use, compiler won't give you a warning if you type squares[0][1] when you really wanted squares[1][0].
If you're needing to avoid duplicates then a HashSet would be a good choice but it not then an ArrayList would work.
Class IntPair(){
int i;
int j;
}
HashSet<IntPair> set = new HashSet<IntPair>();
or
ArrayList<IntPair> list = new ArrayList<IntPair>();
Related
I read an Excel table containing four columns and create a List. Now, I'd like to use the first three columns as key and use the last column as value. I've seen similar questions asked, but in all those questions, either String or Integer is used as a key.
public class initial {
private int from;
private int to;
private int via;
private int cost;
//constructor
//set and get methods
//hashCode and equals methods
}
public class myTuple {
private int from;
private int to;
private int via;
}
//main function
//get the Excel Table as a list
ArrayList<initial> myList = new ArrayList<initial>();
for(int i= mySheet.getFirstRowNum()+1 ; i<= mySheet.getLastRowNum(); i++) {
initial e = new initial();
Row ro = mySheet.getRow(i);
for(int j = ro.getFirstCellNum(); j <= ro.getLastCellNum(); j++) {
Cell ce = ro.getCell(j);
switch(j) {
case 0:
e.setFrom((int) ce.getNumericCellValue());
break;
.....
case 3:
e.setCost((int) ce.getNumericCellValue());
break;
}
}
myList.add(e);
}
//Create map
Map<myTuple, Integer> myMap = new HashMap<>();
I do not know how to proceed after this point. I believe I should use something like;
Map<myTuple, Integer> myMap= myList.stream().collectC(ollectors.toMap(myList:: , myList::));
If someone could assist me, I'd really appreciate.
Also, if you believe that there is a more efficient way to perform this (e.g., the way I read my data and parse into a list, the way I convert the list into a map), please let me know. Even though it is not in the content of this question, if there is a better way to read a multi dimensional table and parse into a List as I do, I 'd love to hear that too. In the future, I will have a bigger tables with more columns. Hence, I'm not quite sure if going through every column with a switch statement is the way to go.
You can just create the map while looping.
Tuple key = new Tuple(row.getNum(0), row.getNum(1), row.getNum(2));
List<Integer> value = new ArrayList<>();
for (int cell = 3; cell < row.getCount(); cell++) {
value.add(row.getNum(cell));
}
Map.put(key,value);
The toMap collector needs 2 functions (1 to create a key & 1 to create a value). You can use lambdas (to extract the relevant fields from your source type):
Map<MyTuple, Integer> myMap = myList
.stream()
.collect(Collectors.toMap(
i -> new myTuple(i.from, i.to, i.via),
i -> i.cost
));
Your destination type "MyTuple" needs a constructor, equals, and hashcode.
Here is an example:
class Tuple implements Comparable<Tuple> {
Object one;
Object two;
Object three;
public Tuple(final Object one, final Object two, final Object three) {
this.one = one;
this.two = two;
this.three = three;
}
#Override
public int compareTo(final Tuple that) {
// TODO: Do your comparison here for the fields one, two and three
return 0;
}
}
Map<Tuple, Object> mapKeyedByCompositeTuple = new HashMap<>();
// TODO: Inside your loop
for (int i = 10; i > 0; i--) {
Tuple key = new Tuple("cell-one-value-" + i, "cell-two-value-" + i, "cell-three-value-" + i);
mapKeyedByCompositeTuple.put(key, "cell-four-value-" + i);
}
System.out.println(mapKeyedByCompositeTuple);
Hope that helps,
Cheers,
Michael
This question is a bit more complex that the title states.
What I am trying to do is store a map of {Object:Item} for a game where the Object represents a cupboard and the Item represents the content of the cupboard (i.e the item inside).
Essentially what I need to do is update the values of the items in a clockwise (positive) rotation; though I do NOT want to modify the list in any way after it is created, only shift the positions of the values + 1.
I am currently doing almost all That I need, however, there are more Object's than Item's so I use null types to represent empty cupboards. However, when I run my code, the map is being modified (likely as it's in the for loop) and in turn, elements are being overwritten incorrectly which after A while may leave me with a list full of nulls (and empty cupboards)
What I have so far...
private static Map<Integer, Integer> cupboardItems = new HashMap<Integer, Integer>();
private static Map<Integer, Integer> rewardPrices = new HashMap<Integer, Integer>();
private static final int[] objects = { 10783, 10785, 10787, 10789, 10791, 10793, 10795, 10797 };
private static final int[] rewards = { 6893, 6894, 6895, 6896, 6897 };
static {
int reward = rewards[0];
for (int i = 0; i < objects.length; i++) {
if (reward > rewards[rewards.length - 1])
cupboardItems.put(objects[i], null);
else
cupboardItems.put(objects[i], reward);
reward++;
}
}
// updates the items in the cupboards in clockwise rotation.
for (int i = 0; i < cupboardItems.size(); i++) {
if (objects[i] == objects[objects.length - 2])
cupboardItems.put(objects[i], cupboardItems.get(objects[0]));
else if (objects[i] == objects[objects.length - 1])
cupboardItems.put(objects[i], cupboardItems.get(objects[1]));
else
cupboardItems.put(objects[i], cupboardItems.get(objects[i + 2]));
}
So how may I modify my code to update so i get the following results..
======
k1:v1
k2:v2
k3:v3
k4:none
=======
k1:none
k2:v1
k3:v2
k4:v3
?
HashMap doesn't guarantee ordering, therefore if you need ordering, use ArrayList or LinkedList.
If you want to stick with HashMap, you need to sort the HashMap based on the key before each rotation. You can sort easily since the keys are Integer objects. But this will affect the performace.
Ragavan has a good answer if you want to stick to your approach. However, you are doing a lot of work to just rotate the items. It would be much more efficient to just rotate the index (using modulus) and keep the arrays the same:
final static List<Integer> objects = new ArrayList<Integer>(
Arrays.asList(10783, 10785, 10787, 10789, 10791, 10793, 10795, 10797));
final static List<Integer> rewards = new ArrayList<Integer>(
Arrays.asList(6893, 6894, 6895, 6896, 6897, -1, -1, -1));
public static int getReward(int obj, int rot){
int rotIndex = (objects.indexOf(obj) - rot)%objects.size();
//modulus in java can be negative
rotIndex = rotIndex < 0 ? rotIndex+objects.size():rotIndex;
return rewards.get(rotIndex);
}
public static void main(String... args){
//This should give 6897, which is the reward for obj 10783 after 4 rotations
System.out.println(getReward(10783,4));
}
I have this code:
_leftArray[0] = _square[6][4];
_leftArray[1] = _square[8][4];
_leftArray[2] = _square[9][5];
I want to be able to extract the values of the array. I'd like to write a method that takes the array position as an argument and returns the coordinates. So if the method was called returnCoordinatesFromArray, I could type returnCoordinatesFromArray[1] and return 6 as a variable and 4 as a variable, so I could use them in another method.
If these are static, hard-coded values, why not do something like this:
Map<Integer, int[]> indexToCoordinateMap = new LinkedHashMap<Integer, int[]>();
indexToCoordinateMap.put(0, new int[]{6, 4});
indexToCoordinateMap.put(1, new int[]{8, 4});
indexToCoordinateMap.put(2, new int[]{9, 5});
Then you don't need the method. You can simply get an array of values where the 0th index is the x coordinate and the 1st index is the y coordinate. Of course, this is by convention. If you want to be more specific, you can use Point and do something like this:
Map<Integer, Point> indexToPointMap = new LinkedHashMap<Integer, Point>();
indexToPointMap.put(0, new new Point(6, 4));
indexToPointMap.put(1, new Point(8, 4));
indexToPointMap.put(2, new Point(9, 5));
Then you can simply do:
Point point = indexToPointMap.get(0);
Do a double for loop and save the x and y positions.
_square value;
int posX=0;
int posY=0;
for(int i=0; i<arr.length; i++) {
for(int j=0; j<arr.length; j++) {
if(arr[i][j]==value) {
posX=i;
posY=j;
}
}
}
"I could type returnCoordinatesFromArray[1] and return 6 as a variable and 4 as a variable"
By design it is not possible in Java to return two values at once. If you need to do something like this you could either build your own little Object that holds two variables:
public class Tupel{
private int firstIndex;
private int lastIndex;
public Tupel(int firstIndex, int lastIndex){
this.firstIndex=firstIndex;
this.lastIndex=lastIndex;
}
public int getFirstIndex(){
return this.firstIndex;
}
// the same for lastIndex
}
Then you you store your Tupels in an array Tupel[] leftArray where for example
leftArray[1] = new Tupel(6,4);
Or you use existing classes like Point if they fit your needs.
Is it possible to store the name of an int variable in a string and use that string as a parameter to update the int?
Yes, this is called reflection.
You are interested in the Field class.
Example:
static class A {
public int x = 0;
}
public static void main(String[] args) throws Exception {
A a = new A();
Field f = A.class.getField("x");
f.set(a, 5);
System.out.println(a.x);
}
Note that though it is possible - it is not advised to use reflection except for rare cases, it has some major draw backs (maintainability, safety, performance...) - which makes the alternatives usually better choices.
Using reflection in this case would be overkill. You can obtain the intended behavior by simply using a Map:
Map<String, Integer> variables = new HashMap<String, Integer>();
Then the keys to the map will be the variable names, and the values the actual values:
variables.put("var1", 10);
variables.put("var2", 20);
Later on, you'll retrieve the values like this:
Integer n1 = variables.get("var1"); // n1 == 10
Integer n2 = variables.get("var2"); // n2 == 20
And if you need to update the values:
variables.put("var1", variables.get("var1") + 32);
Integer n3 = variables.get("var1"); // n3 == 42
The context of your question is not clear - a Map<String, Integer> might do what you need:
Map<String, Integer> map = new HashMap<String, Integer> ();
map.put("int1", 1);
map.put("int2", 2);
//now retrieve the ints based on their name
int int1 = map.get("int1");
I've got an array of int's. I need to add 1 to each of its elements. What's the shortest, most general way to add a given constant to each element, that is, without explicit loops? I've looked online and keep getting pages about adding an element onto an array (i.e., concatenation).
Isn't there something more elegant than looping through each element and adding the constant? Is there some sort of standard library method?
For that matter, how would one add two arrays together (i.e., matrix addition) without an explicit loop?
Here is how you can write the two cases above with Functional Java.
1. Adding 1 to each element:
It's a functional programming library, and so it does not provide mutating operations. But you can easily add them yourself.
public static <A> void transform(Array<A> xs, F<A, A> f) {
for(int i = 0; i < xs.length(); i++) {
xs.set(i, f.f(xs.get(i)));
}
}
Use:
transform(yourArray, Integers.add.f(1));
2. Adding two matrices:
Let xss and yss be two matrices, both of types Array<Array<Integer>>. Then you can add them with:
xss.zip(yss).map(new F<P2<Array<Integer>, Array<Integer>>, Array<Integer>>() {
public Array<Integer> f(P2<Array<Integer>, Array<Integer>> p) {
Array<Integer> xs = p._1();
Array<Integer> ys = p._2();
return xs.zip(ys).map(new F<P2<Integer, Integer>, Integer>() {
public Integer f(P2<Integer, Integer> q) {
return q._1() + q._2();
}
});
}
});
This may feel more verbose than necessary, and that is because Java does not support lambda expressions yet. In the meantime, IDEs can help make such techniques more approachable.
If an unmodifiable result is ok, and you're not stuck to using arrays, you could use a cute trick to delay the addition until the last possible moment. But as soon as you need to visit the whole result array, any performance benefit is lost and the code ends up being more complicated than necessary.
public class OffsetArrayList extends AbstractList< Integer > {
private final List< Integer > liUnderlying;
private final int iOffset;
public OffsetArrayList( int iOffset, liUnderlying ) {
this.iOffset = iOffset;
this.liUnderlying = liUnderlying;
}
#Override
public Integer get( int iIndex ) {
return liUnderlying.get( iIndex ) + iOffset;
}
#Override
public Integer set( int iIndex, Integer iNewValue ) {
return liUnderlying.set( iIndex, iNewValue - iOffset ) + iOffset;
}
// etc.
}
// create new array
int[] aiInput = new int[] { 23, 98, -45 };
// two object allocations, but no new array created and no additions performed
OffsetArrayList alPlusOne = new OffsetArrayList( 1, Arrays.asList( aiInput ) );
// one addition performed; constant time
assert( alPlusOne.get( 0 ) == 24 );
// benefit murky, as we are adding to the same element repeatedly
for ( int i = 0; i < 1000000; ++i )
assert( alPlusOne.get( 2 ) == -44 );
// benefit lost, input destroyed
int[] aiOutput = alPlusOne.toArray( aiInput );