1

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.

3
  • Create a class Tuple that will hold those three values and override equals and hashcode methods for it. Then you will be able to use it as key in hashing collections. Commented May 12, 2019 at 6:42
  • 1
    Do you actually need to create the list, ie do you need it later? Seems to me it's easier to just create the map in the loop. Commented May 12, 2019 at 6:43
  • Is this a one off "import"? I often just get Excel to generate Java code and paste that into my scripts. For instance: ="myMap.put(new MyTuple(" & A3 & "," & B3 & "," & C3 & ")," & D3 & ")" (easy for ints; slightly more faff quoting string fields). Commented May 12, 2019 at 9:17

3 Answers 3

2

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);
Sign up to request clarification or add additional context in comments.

2 Comments

You're totally right! It was 3.00 am in the morning and I guess my mind was not in the right place. Thanks!
The question has exactly 4 columns. You can remove the List and loop. The Map should be Map<Tuple,Integer> not Map<Tuple,List<Integer>>.
1

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.

2 Comments

Thanks! This is what I was exactly looking for. At the moment, creating the map within the for loop makes much more sense as @daniu suggested.
Agreed. If you're already forced to loop the source data, go direct to a Map. Maybe this will help you in a future problem.
-1

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

1 Comment

There's no reason to use Object here. All the fields are Integers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.