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}