重构Java代码以使其可重用



我最近创建了一个简单的方法,它以HashMap和LinkedList作为参数。它遍历HashMap,找到遵循以下规则的任意两个条目:

  1. 此项的键之和必须可被100整除
  2. 键的总和必须小于1000
  3. 如果具有相同值的条目出现多次,则应跳过该情况

遵循这些规则的对将添加到LinkedList中。它看起来像这样:

private static void compare2(HashMap<Integer,String> values,List<String>results){
if (values.size()>1) {
for(HashMap.Entry<Integer,String> entry1:values.entrySet()){
for (HashMap.Entry<Integer,String> entry2:values.entrySet()){
if (entry1.getValue().equals(entry2.getValue()))continue;
if ((entry1.getKey() + entry2.getKey())%100 == 0 && (entry1.getKey() + entry2.getKey())<1000){
results.add(entry1.getKey() + "+" + entry2.getKey() + "=" + entry1.getKey() + entry2.getKey());
results.add(entry1.getValue());
results.add(entry2.getValue());
}
}
}
}
}

现在我想创建一个类似的方法,找到3个遵循相同规则的条目。问题是,我想重用现有的代码,而不是复制/粘贴这个和modyfyng,但我似乎找不到实现这一点的方法。只要结果是一样的,我不介意是否需要改变我的方法。

您可以将数字的数量作为一个参数:N.

您可以继续使用for循环,但另一种示例方法可以是使用lambda和流重构方法,如下所示:

List<List<Map.Entry<Integer, String>>> compareN(HashMap<Integer, String> map, int n) {
return map.entrySet().stream()
.map(entry -> listOfNAccompanyingEntriesThatSatisfyTheConditions(entry, emptyList(), map, n - 1))
.filter(list -> !list.isEmpty())
.collect(toList());
}

其中方法listOfNAccompanyingEntriesThatSatisfyTheConditions是递归方法:

private List<Map.Entry<Integer, String>>
listOfNAccompanyingEntriesThatSatisfyTheConditions(Map.Entry<Integer, String> newEntry,
List<Map.Entry<Integer, String>> selectedEntries,
HashMap<Integer, String> originalMap,
int n) {
List<Map.Entry<Integer, String>> newSelectedEntries = join(newEntry, selectedEntries);
if (n == 0) return satisifiesCondition(newSelectedEntries) ? selectedEntries : emptyList();
return originalMap.entrySet().stream()
.filter(entry -> !selectedEntries.contains(entry) && !entry.equals(newEntry))
.map(entry -> listOfNAccompanyingEntriesThatSatisfyTheConditions(entry, newSelectedEntries, originalMap, n - 1))
.flatMap(Collection::stream)
.collect(toList());
}

对于每个n,该方法对原始完整列表进行另一次尝试,以累积可能满足要求的子列表。如果达到数量(n=0),则递归停止,并验证停止条件:

private static boolean satisifiesCondition(List<Map.Entry<Integer, String>> entries) {
int sum = sumOfTheKeysFrom(entries);
return sum % 100 == 0 && sum < 1000;
}

然而,这种方法实际上是对您的实现的精确转换,并且仍然存在相同的几个问题。例如,如果您为运行它

HashMap<Integer, String> map = new HashMap<Integer, String>() {{
put(1, "fred");
put(2, "anja");
put(24, "tom");
put(45, "eddy");
put(22, "lenny");
put(77, "tommy");
put(55, "henry");
put(43, "alfred");
}};

您将产生双倍的结果和两次相同条目的结果,例如:

[1=fred,22=lenny,1=fred,77=tommy][2=anja,55=henry,2=anja,43=alfred]

然而,这些问题很容易通过一些小的调整来解决。

如果您不熟悉流、lambda或递归,我建议您使用命令式方法实现同样的方法。还要注意,我并不关心示例代码中的性能,因为我认为这个问题是一种练习。

试试这样的东西:

@SafeVarargs
private static void check( final List<String> results,
final Map.Entry<Integer, String>... vals )
{
int sum = 0;
for ( final Map.Entry<Integer, String> val : vals )
{
final Integer key = val.getKey();
sum += null == key ? 0 : key;
}
if ( sum < 1000 && 0 == ( sum % 100 ) )
{
final StringBuilder result = new StringBuilder( 200 );
for ( final Map.Entry<Integer, String> val : vals )
{
result.append( " + " ).append( val.getKey() );
}
results.add( result.append( " = " ).append( sum ).substring( 3 ) );
for ( final Map.Entry<Integer, String> val : vals )
{
results.add( val.getValue() );
}
}
}
private static void compare2( final HashMap<Integer, String> values,
final List<String> results )
{
if ( values.size() > 1 )
{
for ( final HashMap.Entry<Integer, String> entry1 : values.entrySet() )
{
for ( final HashMap.Entry<Integer, String> entry2 : values.entrySet() )
{
if ( entry1 == entry2 )
continue;
check( results, entry1, entry2 );
}
}
}
}
private static void compare3( final HashMap<Integer, String> values,
final List<String> results )
{
if ( values.size() > 2 )
{
for ( final HashMap.Entry<Integer, String> entry1 : values.entrySet() )
{
for ( final HashMap.Entry<Integer, String> entry2 : values.entrySet() )
{
for ( final HashMap.Entry<Integer, String> entry3 : values.entrySet() )
{
if ( entry1 == entry2 || entry1 == entry3 || entry2 == entry3 )
continue;
check( results, entry1, entry2, entry3 );
}
}
}
}
}

最新更新