Home > Enterprise >  How to make a calculation on the list of HashMaps in Java?
How to make a calculation on the list of HashMaps in Java?

Time:12-15

I currently have the following sorted set of maps of data:

[
   {"name":"john", "date":2015, "status":"success"},
   {"name":"john", "date":2013, "status":"fail"},
   {"name":"chris", "date":2013, "status":"success"},
   {"name":"john", "date":2012, "status":"fail"},
   {"name":"john", "date":2009, "status":"success"},
   {"name":"chris", "date":2007, "status":"fail"},
   {"name":"john", "date":2005, "status":"fail"},
]

I'm trying to calculate the failure duration for each of the names until 2022. Status for each name is in failure until the next success status.

So, let's say for the name john, it was failed on 2005, next success was 2009, which means 4 years of failure. Then it got failed again on 2012, and again on 2013, which overall until 2015 would be 3 years of failure. Combining them would result in 7 years for john.

With the same logic, for chris we have 6 years of failure.

I'm stuck in the implementation of this. Does anyone have an efficient solution for this problem?

CodePudding user response:

Suppose you have a Record class for each entry

public class Record {
    public String name;
    public Integer date;
    public String status;

    public Record(String name, Integer date, String status) {
        this.name = name;
        this.date = date;
        this.status = status;
    }
}

You can use Stream API to achieve your goals

public static Map<String, Integer> useStream(List<Record> records) {
    return records.stream()
        .collect(Collectors.groupingBy(r -> r.name))
        .entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey, e -> {
            Integer[] lastFail = new Integer[]{null};
            return e.getValue().stream()
                .sorted(Comparator.comparing(r -> r.date))
                .mapToInt(t -> {
                    if (t.status.equals("fail") && lastFail[0] == null) {
                        lastFail[0] = t.date;
                    } else if (t.status.equals("success") && lastFail[0] != null) {
                        int last = lastFail[0];
                        lastFail[0] = null;
                        return t.date - last;
                    }
                    return 0;
                })
                .sum();
        }));
}

Or you can use better Seq API with smoother code

public static Map<String, Integer> useSeq(List<Record> records) {
    return Seq.of(records)
        .groupBy(r -> r.name)
        .toList()
        .toMap(Map.Entry::getKey, e -> {
            Integer[] lastFail = new Integer[]{null};
            return Seq.of(e.getValue())
                .sortBy(r -> r.date)
                .sumInt(t -> {
                    if (t.status.equals("fail") && lastFail[0] == null) {
                        lastFail[0] = t.date;
                    } else if (t.status.equals("success") && lastFail[0] != null) {
                        int last = lastFail[0];
                        lastFail[0] = null;
                        return t.date - last;
                    }
                    return 0;
                });
        });
}

Both of these methods result as {chris=6, john=7}

  • Related