我想不出更好的标题。对此感到抱歉。如果有人能想到更好的标题,请随时改变它。
Rule {
String key;
String t1; // First level
String t2;
String t3; // Last level
Object value;
}
RuleHolder {
Collection<Rule> rules;
}
示例数据可以在RuleHolder中,如下所示(顺序可以不同)
key t1 t2 t3 value
A a - - m
A a b - mm
A a b c mmm
B a - - n
C a - - p
C a b - pp
期望的结果:
Key A -> mmm
Key B -> n
Key C -> pp
现在我怎样才能以高效的方式达到理想的效果?为了增加更多的复杂性,我如何获得单个密钥的最佳值t1,t2,t3如getBestValue(key,t1,t2,t3)
可能对于t1,t2,t3的组合没有值。
我的尝试如下:
步骤1: 首先从收集规则准备一个Map;
Map<key, Collection<Rule>>
步骤2:在关键环境中,完成所有规则,然后选取最后一级定义的值。
答案 0 :(得分:1)
使用Stream API,您确实需要有2个单独的Stream管道:
Map<String, Rule>
,其中一个键指向要保留的规则Map<String, Object>
,我们只保留规则的值使用toMap
收集器创建第一个映射,并通过选择具有最多非null级别元素的值来处理重复键。因此它首先检查t3
并选择非空的规则;如果不存在,则保留t2
非空的规则;因为那些是硬编码的变量,除了涉及反射之外我们不能使它真正动态。
最后,最后一张地图也是由toMap
收藏家创建的,只需简单地重新映射该值。
Map<String, Rule> ruleMap =
rules.stream().collect(Collectors.toMap(
r -> r.key,
r -> r,
(r1, r2) -> { // a bit ugly but it comes from the fact that t1, t2 an t3 are hard-coded
if (r1.t3 != null) return r1;
if (r2.t3 != null) return r2;
if (r1.t2 != null) return r1;
if (r2.t2 != null) return r2;
if (r1.t1 != null) return r1;
if (r2.t1 != null) return r2;
return r1;
}
));
Map<String, Object> result =
ruleMap.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().value));
System.out.println(result); // prints "{A=mmm, B=n, C=pp}" for your example
为了让它变得动态,我们需要添加一些魔力。给定一个字段列表,我们可以将其映射到List<MethodHandle>
List<String> fields = Arrays.asList("t3", "t2", "t1");
MethodHandles.Lookup lookup = MethodHandles.lookup();
List<MethodHandle> handles = fields.stream().map(s -> {
try {
return lookup.findGetter(Rule.class, s, String.class);
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}).collect(Collectors.toList());
然后我们可以使用该列表在重复的情况下返回最合适的规则:
Map<String, Rule> ruleMap =
rules.stream().collect(Collectors.toMap(
r -> r.key,
r -> r,
(r1, r2) -> {
return handles.stream().map(h -> {
try {
if (h.invoke(r1) != null) return r1;
if (h.invoke(r2) != null) return r2;
return null;
} catch (Throwable t) {
throw new AssertionError(t);
}
}).filter(Objects::nonNull).findFirst().orElse(r1);
}
));