2 回答
TA贡献1804条经验 获得超3个赞
有时,如果爆炸式循环使代码更具可读性,则不一定是一件坏事。
我建议您将代码保持原样,因为稍后您会看到,如果您尝试对其进行压缩,则很可能会遇到更糟糕的情况。如果您坚持要继续阅读。
我的想法很简单:您实际上是在尝试遍历多个掩码以用于您的匹配模式。在这种情况下,掩码为“是否使用id或默认值”。
不掩饰任何东西,如果没有匹配,
遮罩c,如果没有匹配项,
遮罩b,如果不匹配,
屏蔽bc,如果没有匹配项,
屏蔽abc,如果没有匹配项,
返回空值。
因此,我们可以使用某种数据结构来存储掩码,如下所示:
// true = use id (don't mask); false = use default (mask).
List<ImmutableTriple<Boolean, Boolean, Boolean>> matchMasks = new ArrayList<>();
matchMasks.add(new ImmutableTriple<>(true, true, true));
matchMasks.add(new ImmutableTriple<>(true, true, false));
matchMasks.add(new ImmutableTriple<>(true, false, true));
matchMasks.add(new ImmutableTriple<>(true, false, false));
matchMasks.add(new ImmutableTriple<>(false, false, false));
当然,你可以使用List的List,Array的Array,或任何明智的存储这个面具。
现在,我们可以使用循环来压缩您的代码:
private Integer match(int a, int b, int c)
{
Integer value = null;
// Loop through match rules.
for (ImmutableTriple<Boolean, Boolean, Boolean> mask : matchMasks)
{
// Check whether to apply mask.
int aId = mask.getLeft() ? a : 0;
int bId = mask.getMiddle() ? b : 0;
int cId = mask.getRight() ? c : 0;
// Try to match cache.
value = cache.get(new ImmutableTriple<>(aId, bId, cId));
// Stop if match found.
if (value != null) break;
}
return value;
}
全部归为一类:
public class Test
{
private HashMap<ImmutableTriple<Integer, Integer, Integer>, Integer> cache = <your table here>;
private List<ImmutableTriple<Boolean, Boolean, Boolean>> matchMasks = new ArrayList<>();
public Test()
{
// true = use id (don't mask); false = use default (mask).
this.matchMasks.add(new ImmutableTriple<>(true, true, true));
this.matchMasks.add(new ImmutableTriple<>(true, true, false));
this.matchMasks.add(new ImmutableTriple<>(true, false, true));
this.matchMasks.add(new ImmutableTriple<>(true, false, false));
this.matchMasks.add(new ImmutableTriple<>(false, false, false));
}
private Integer match(int a, int b, int c)
{
Integer value = null;
// Loop through match rules.
for (ImmutableTriple<Boolean, Boolean, Boolean> mask : this.matchMasks)
{
// Check whether to apply mask.
int aId = mask.getLeft() ? a : 0;
int bId = mask.getMiddle() ? b : 0;
int cId = mask.getRight() ? c : 0;
// Try to match cache.
value = this.cache.get(new ImmutableTriple<>(aId, bId, cId));
// Stop if match found.
if (value != null) break;
}
return value;
}
}
PS对于此特定情况,由于0 =默认值,因此可以为掩码使用1和0而不是true和false int aId = mask.getLeft() * a;,但这很简单。
如您所见,尽管我们确实将代码“压缩”成一个循环,但其效果还是值得商de的。实际上,我认为该代码实际上不那么可读。因此,有时候,坚持使用爆炸循环并不一定很糟糕。
TA贡献1830条经验 获得超3个赞
您可以使用默认值为三胞胎的所有可能状态创建“掩码映射”:
private static List<Integer[]> mask = new ArrayList<>();
static {
mask.add(new Integer[] {null, null, null});
mask.add(new Integer[] {0, null, null});
mask.add(new Integer[] {null, 0, null});
mask.add(new Integer[] {null, null, 0});
mask.add(new Integer[] {null, 0, 0});
mask.add(new Integer[] {0, null, 0});
mask.add(new Integer[] {0, 0, null});
mask.add(new Integer[] {0, 0, 0});
}
假设为null,表示必须填充键值。然后,您可以从此掩码创建三元组键的列表:
List<Triple<Integer, Integer, Integer>> triples = mask.stream()
.map(row -> genrateTriple(row, a, b, c))
.collect(Collectors.toList());
generateTriplets的代码:
private Triple<Integer, Integer, Integer> genrateTriple(Integer[] row, int... values) {
int[] tripleElems = new int[3];
for (int i = 0; i < row.length; i++) {
tripleElems[i] = row[i] == null ? values[i] : row[i];
}
return new ImmutableTriple<>(tripleElems[0], tripleElems[1], tripleElems[2]);
}
并在搜索中使用它:
return triples.stream()
.map(triple -> cache.get(triple))
.findFirst()
.orElse(null);
但是我不确定这是否比您的“代码气味”;)好。
编辑:当然,如果您避免创建中间集合,这会更有效(findFirst是短循环运算符):
Integer result = mask.stream()
.map(row -> genrateTriple(row, a, b, c))
.map(cache::get)
.findFirst()
.orElse(null);
添加回答
举报