-2
public class Main {
    public static void main(String[] args) {
        Data object= new Data();
        object.setQuantity(5);
        object.setDate("05/06/2020");
        object.setMaterial("96111");
        Data object1= new Data();
        object1.setQuantity(2);
        object1.setDate("05/06/2020");
        object1.setMaterial("96111");
        Data object2= new Data();
        object2.setQuantity(3);
        object2.setDate("05/06/2020");
        object2.setMaterial("96111");
        Data object3= new Data();
        object3.setQuantity(3);
        object3.setDate("05/06/2020");
        object3.setMaterial("96112");
        Data object4= new Data();
        object4.setQuantity(9);
        object4.setDate("05/07/2020");
        object4.setMaterial("96113");
        
        ArrayList<Data> list= new ArrayList<Data>();
        list.add(object);
        list.add(object1);
        list.add(object2);
        list.add(object3);
        list.add(object4);        
       
        HashMap<String, Data> map = new HashMap<>();
        for(Data obj : list) {
            if (map.containsKey(obj.getDate())) {
                map.put(obj.getDate(),new Data(map.get(obj.getDate()).getQuantity() + (obj.getQuantity()), obj.getDate(), obj.getMaterial()));  
            } else {
                map.put(obj.getDate(),obj);
            }        
        }
        System.out.println(map);          
    } 
}

Based on date and material , quantity should be added. Output should come as shown in below:

05/07/2020=(material:96113 date:05/07/2020 quantity:9), 05/06/2020=(material:96112 date:05/06/2020 quantity:3), 05/06/2020=(material:96111 date: 05/06/2020 quantity:10}

But I am getting output as:

05/07/2020=(material:96113 date:05/07/2020 quantity:9), 05/06/2020=(material:96112 date:05/06/2020 quantity:13)}
Lino
  • 19,604
  • 6
  • 47
  • 65

3 Answers3

1

From what you've provided you can have a Map of Maps, grouped by date and then by material, and as you've only 1 value left, the quanity (the other values are already provided by the key in the Map) you can use this format:

//   Date     Material   Quantity
//     |           |       |
//     V           V       V
Map<String, Map<String, Integer>> map = new HashMap<>();

Then your for-loop can be converted to this:

for (Data data : list) {
    map.computeIfAbsent(data.getDate(), i -> new HashMap<>())
       .merge(data.getMaterial(), data.getQuantity(), Integer::sum);
}

Which then prints something like this:

{05/07/2020={96113=9}, 05/06/2020={96111=10, 96112=3}}

The resulting map can then easily be converted back into a List<Data>:

List<Data> result = new ArrayList<>();
for (Map.Entry<String, Map<String, Integer>> entries : map.entrySet()) {
    for (Map.Entry<String, Integer> entry : entries.getValue().entrySet()) {
        result.add(new Data(entry.getValue(), entries.getKey(), entry.getKey()));
    }
}

When printed, results into something like this:

[(material=96113, date=05/07/2020, quantity=9), (material=96111, date=05/06/2020, quantity=10), (material=96112, date=05/06/2020, quantity=3)]
Lino
  • 19,604
  • 6
  • 47
  • 65
  • @Eklavya it is very suited for usages like these – Lino Jun 29 '20 at 08:30
  • Of course, sometimes I am confused with post an answer using stream API (when OP don't use it) – Eklavya Jun 29 '20 at 08:36
  • How to check output. I have used S.O.P(map); I am getting output as {05/07/2020=com.iib.reservation.Data@4517d9a3, 05/06/2020=com.iib.reservation.Data@372f7a8d}. – roja simple Jun 29 '20 at 09:19
  • @rojasimple I am sorry, I don't really understand what your problem is. Is the output you've shown from your old code or from the one I've provided? Also is the `toString()` method correctly implemented? – Lino Jun 29 '20 at 09:24
0

You can use stream API to solve this. Using Collectors.toMap map by Date and Materials. Merge the quantity and collect. Then get the map values set in list.

List<Data> res = new ArrayList<>(list.stream()
        .collect(Collectors.toMap(
            e -> new SimpleEntry<String, String>(e.getDate(), e.getMaterial()), e -> e,
            (a, b) -> new Data(a.getQuantity() + b.getQuantity(), a.getDate(), a.getMaterial())))
        .values());

You can test code online here

Eklavya
  • 17,618
  • 4
  • 28
  • 57
-2

Based on what I have understood, I think this is what you are asking for :

for(Data obj : list) {
    if (map.containsKey(obj.getDate())) { // If that key exists
        if(map.get(obj.getDate()).getMaterial() == obj.getMaterial()){ // and if the material is also same
            map.put(obj.getDate(),new Data(map.get(obj.getDate()).getQuantity() + (obj.getQuantity()), obj.getDate(), obj.getMaterial())); // update the item
        }
        else{
            map.put(obj.getDate(),obj); // if material is not same
        }
    } 
    else {
        map.put(obj.getDate(),obj); // if key don't exists, add a new item
    }        
}

It first looks for the date, if date is exists, then it look for the material, and if the material is also the same, the the object is updated....In other cases, a new item is added.

NOTE : This is slightly the right answer but not absolutely right, as this code won't be able to differentiate between the same date and different materials.

The only perfect solution would be to use nested key/value pairs.

Hope it helps :)

faiz-e
  • 190
  • 4
  • 21
  • [Use `.equals()` instead of `==`](https://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java) – Lino Jun 29 '20 at 08:02
  • How the muliple same date key contains in map ? – Eklavya Jun 29 '20 at 08:03
  • `if material is not same, just add a new item` -> It **won't** be added, but the old will be overwritten! – Lino Jun 29 '20 at 08:07
  • @Lino Oops, you are right !! Thanks for pointing that out. That was so obvious. How did I miss it !! :) – faiz-e Jun 29 '20 at 08:17
  • I have tried this code as well . I am getting output as {05/07/2020=com.iib.reservation.Data@4517d9a3, 05/06/2020=com.iib.reservation.Data@372f7a8d} – roja simple Jun 29 '20 at 09:19