Result (@NotNull TraceInfo info) { final Map<Integer, TraceElement> before = info.getValuesOrderBefore(); final Map<Integer, TraceElement> after = info.getValuesOrderAfter(); final Map<TraceElement, List<TraceElement>> direct = new HashMap<>(); final Map<TraceElement, List<TraceElement>> reverse = new HashMap<>(); final Map<Object, List<TraceElement>> grouped = StreamEx .of(after.keySet()) .sorted() .map(after::get) .groupingBy(IdentityResolver::extractKey); final Map<Object, Integer> key2Index = new HashMap<>(); for (final TraceElement element : before.values()) { final Object key = extractKey(element); final List<TraceElement> elements = grouped.get(key); if (elements == null || elements.isEmpty()) { direct.put(element, Collections.emptyList()); continue; } final int nextIndex = key2Index.getOrDefault(key, -1) + 1; key2Index.put(key, nextIndex); final TraceElement afterItem = elements.get(nextIndex); direct.put(element, Collections.singletonList(afterItem)); reverse.put(afterItem, Collections.singletonList(element)); } return Result.of(direct, reverse); }