简体   繁体   中英

How to correct the below code to get output as expected?

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)}

From what you've provided you can have a Map of Map s, 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)]

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

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:)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM