I currently have 2 Maps intersectionDiffLeft, intersectionDiffRight with the structure of Map<Boolean, List<Map<String, Object>>
Where if the boolean is true it means it is considered a matching record. If it is true there will be 1 true record from left side and one true record on right side. There can be zero to many in this map. Same goes for if the boolean is false, meaning those records don't match another one on the opposite side, however the same amount on each doesn't need to be the same like if the boolean is true.
I'm looking for a way to create a list of objects such as this one to return after I have finished.
@Value
public class ReconciliationResult {
Map<String, Object> recordValue;
List<Object> keyValues;
Origin origin;
ReconciliationResultStatus status;
public enum ReconciliationResultStatus {
INVALID_KEY("INVALID_KEY"),
DUPLICATE_KEY("DUPLICATE_KEY"),
MATCHING("MATCHING"),
NON_MATCHING("NON_MATCHING");
private final String text;
ReconciliationResultStatus(String text) {
this.text = text;
}
}
public enum Origin {
LEFT_SIDE("lhs"),
RIGHT_SIDE("rhs");
private final String side;
Origin(String side) {
this.side = side;
}
}
I currently have it implemented in a way where I am duplicating code and it works, but am looking for a more elegant solution instead of all of this duplication, note the creation of intersectionDiffRight is the same as intersectionDiffLeft except we use rhsMap, instead of lhsMap.
Please let me know if you need any other code from me.
Map<Boolean, List<Map<String, Object>>> intersectionDiffRight =
rhsMap
.entrySet()
.stream()
.collect(
Collectors.partitioningBy(
entry -> lhsMap.containsKey(entry.getKey()),
Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
List<Map<String, Object>> intersection = new ArrayList<>();
intersection.addAll(intersectionDiffLeft.get(true));
intersection.addAll(intersectionDiffRight.get(true));
List<Map<String, Object>> difference = new ArrayList<>();
difference.addAll(intersectionDiffLeft.get(false));
difference.addAll(intersectionDiffRight.get(false));
List<ReconciliationResult> reconResults = new ArrayList<>();
for (Map<String, Object> map : intersectionDiffLeft.get(true)) {
reconResults.add(new ReconciliationResult(map, Collections.singletonList(map.keySet()), ReconciliationResult.Origin.LEFT_SIDE, ReconciliationResult.ReconciliationResultStatus.MATCHING));
}
for (Map<String, Object> map : intersectionDiffLeft.get(false)) {
reconResults.add(new ReconciliationResult(map, Collections.singletonList(map.keySet()), ReconciliationResult.Origin.LEFT_SIDE, ReconciliationResult.ReconciliationResultStatus.NON_MATCHING);
}
for (Map<String, Object> map : intersectionDiffRight.get(true)) {
reconResults.add(new ReconciliationResult(map, Collections.singletonList(map.keySet()), ReconciliationResult.Origin.RIGHT_SIDE, ReconciliationResult.ReconciliationResultStatus.MATCHING));
}
for (Map<String, Object> map : intersectionDiffRight.get(false)) {
reconResults.add(new ReconciliationResult(map, Collections.singletonList(map.keySet()), ReconciliationResult.Origin.RIGHT_SIDE, ReconciliationResult.ReconciliationResultStatus.NON_MATCHING));
}
```
1 Answer 1
Your INVALID_KEY
and DUPLICATE_KEY
are never used, so delete them and reduce that enum
to a boolean
.
Keep your Origin
enum, but delete the explicit constructor and the string member.
Partitioning is not useful here. You can just find the intersection of the two key sets, and then check for membership in a utility function.
If you want an implicit constructor for ReconciliationResult
, I suggest just using a record
instead.
keyValues
is not useful as a member; delete it. If you really need that later, add a convenience method to derive it from your recordValue
.
Suggested
import java.util.*;
import java.util.stream.Stream;
public class Main {
private record ReconciliationResult(
Map<String, Object> recordValue,
Origin origin,
boolean matched
){
public enum Origin {
LEFT, RIGHT;
}
static Stream<ReconciliationResult> forSide(
Map<String, Map<String, Object>> side,
Set<String> shared,
Origin origin
) {
return side.entrySet().stream()
.map(entry -> new ReconciliationResult(
entry.getValue(), origin, shared.contains(entry.getKey())
));
}
}
private static Stream<ReconciliationResult> findIntersection(
Map<String, Map<String, Object>> lhsMap,
Map<String, Map<String, Object>> rhsMap
) {
var sharedKeys = new HashSet<String>(lhsMap.keySet());
sharedKeys.retainAll(rhsMap.keySet());
return Stream.concat(
ReconciliationResult.forSide(lhsMap, sharedKeys, ReconciliationResult.Origin.LEFT),
ReconciliationResult.forSide(rhsMap, sharedKeys, ReconciliationResult.Origin.RIGHT)
);
}
public static void main(String[] args) {
var result = findIntersection(
Map.of(
"left1", Map.of("1", 2, "3", 4),
"shared", Map.of("a", "b")
),
Map.of(
"right1", Map.of("5", 6, "7", 8),
"shared", Map.of("c", "d")
)
).toList();
}
}
-
\$\begingroup\$ I think this is close, I have yet to check it, but I would like to compare the entry set, and the whole reason I went with the data structure I did, is because if the value for each key that I need, i.e. (entity, instrument, etc...) don't match the other side it shouldn't be qualified as a match. That is why in this case, if I'm understanding it correctly if the ID fields are different they wouldn't be an intersection (match). We need not only the keys, but the values as well, with the ability to exclude certain keys. I will post my full code in an edit. @Reinderien \$\endgroup\$Beez– Beez2022年08月31日 05:15:55 +00:00Commented Aug 31, 2022 at 5:15
-
\$\begingroup\$ So far as I'm aware this accomplishes the same thing. I encourage you to run it with a breakpoint at the end and examine the results. If there is an error please let me know what the output should actually be. \$\endgroup\$Reinderien– Reinderien2022年08月31日 11:43:06 +00:00Commented Aug 31, 2022 at 11:43
-
1\$\begingroup\$ I see what happened - my guess about your key structure was wrong. I'll give it another shot tonight. \$\endgroup\$Reinderien– Reinderien2022年08月31日 12:28:50 +00:00Commented Aug 31, 2022 at 12:28
@Value
? \$\endgroup\$