1

我发现在使用 java 集合时,尤其是在使用泛型编写实用程序方法时,我的代码通常是丑陋和臃肿的,充满了空检查、嵌套循环和重复。专注于这个例子,我想要改进的想法。

假设我们有一个EnumMap其值是评级列表。例如,假设enums 本身代表水果,每个值代表不同人给出的列表评级。

APPLE  -> [1,   3,   4] 
ORANGE -> [2,   0,   5]

John rated apple 1, Mary rated apple 3, Steve rated apple 4
John rated orange 2, Mary rated orange 0, Steve rated orange 5
Note the specific names are irrelevant and provided only to clarify the setup

现在我们要编写一个实用方法,该方法接受与上述类似的数据结构,并返回每个人最喜欢的水果的列表。因此,上述样本数据的预期结果将是:[ORANGE, APPLE, ORANGE因为2 > 13 > 05 > 4

以下是我目前执行此操作的方法。我想要一种同样(或更高)有效但更简洁的方式来编写相同的算法。

谢谢!

public class MyListUtil {

    public static <K extends Enum<K>, T extends Object & Comparable<? super T>> List<K> maxKeysByIndex(EnumMap<K, List<T>> enumMap) {
        Iterator<K> keysIter = enumMap.keySet().iterator();
        int sizeOfAllLists = enumMap.get(keysIter.next()).size();
        List<K> ret = new ArrayList<K>();

        for (int i=0; i<sizeOfAllLists; i++) {
            keysIter = enumMap.keySet().iterator();
            K maxIndexKey = null;
            T maxIndexVal = null;

            while (keysIter.hasNext()){
                K curKey = keysIter.next();
                T curVal = enumMap.get(curKey).get(i);
                if (maxIndexVal == null || curVal.compareTo(maxIndexVal) > 0) {
                    maxIndexVal = curVal;
                    maxIndexKey = curKey;
                }
            }
            ret.add(maxIndexKey);
        }

        return ret;
    }
}
4

4 回答 4

2

这真的很丑。

IMO 在这里使用枚举是错误的。枚举应该是编程常量,而不是人们的偏好。

您应该创建一个使用 Map 的类 PersonFruitPreference 以允许 Person 设置水果的偏好。还添加一个方法 getFavoriteFruit()

于 2012-05-09T20:51:56.153 回答
1

首先使用排序列表。

第二个简单的调用:

列出结果;for(T in enummap) { result.add(enummap.get(t).get(0)); //假设你做了一个降序排序}

返回结果。

于 2012-05-09T20:52:49.827 回答
1

如果您需要很多方法都对相同的泛型类型进行操作,我认为您可以将辅助方法放入一个类中,K然后T只为整个类指定完整的泛型类型。要使用它们,您将创建该类的对象,然后从中调用方法。

该对象将是无状态的,但它为您提供了一种将所有详细信息放在一个位置的语法方式。

public class <K extends Enum<K>, T extends Object & Comparable<? super T>> MyListUtil {

    public List<K> maxKeysByIndex(EnumMap<K, List<T>> enumMap) {
        ...
    //other methods
}

您可以尝试将内部循环放入单独的方法中,例如:

public K getMaxKeyFromPos(EnumMap<K, List<T>> enumMap, int pos)
{
    K maxIndexKey = null;
    T maxIndexVal = null;

    for (K curKey : enumMap.keySet()) {
         T curVal = enumMap.get(curKey).get(pos);
         if (maxIndexVal == null || curVal.compareTo(maxIndexVal) > 0) {
             maxIndexVal = curVal;
             maxIndexKey = curKey;
         }
    }
    return maxIndexKey;
}

我还把它改成了for-each语法,去掉了一些迭代器的麻烦。

于 2012-05-09T21:03:10.450 回答
1

宣传 Scala 的绝佳机会。您可能知道,Scala 在 JVM 上运行,并且与 Java 字节码完全兼容。它自己编译为 JVM 字节码。

从这个精简的工作代码中看不到什么:

val apple  = List (1, 3, 4)
val orange = List (2, 0, 5)
val persons = List ("John", "Mary", "Steve") 
val prefs = apple.zip (orange) .zip (persons) 
//  List[((Int, Int), java.lang.String)] = List(((1,2),John), ((3,0),Mary), ((4,5),Steve))
prefs.map (e => e._2 + ": " + (if (e._1._1 > e._1._2) "apple" else "orange"))
// List[java.lang.String] = List(John: orange, Mary: apple, Steve: orange)

也就是说,您拥有完整的静态编译时安全性。但是类型会在可能的情况下被推断出来,所以你的样板文件要少得多。

前 3 行产生 3 个列表。然后他们被压缩 - 在你看到的评论中,类型推断者说他发现了什么。

这部分有点神秘:

 (e => e._2 + ": " + (if (e._1._1 

Prefs 是 ((Pair of Int), String) 的列表,e 是列表中的一个元素。e._2 是字符串部分(出于某种原因,在此类元组中,我们不从 0 开始计数,而是从 1 开始计数 - 我猜,因为从元组起源的地方,有这个习惯),而列表和数组等从 0 开始计数也像Java一样。

e._1 是元素的第一部分,即 Ints 对,它们是水果的首选项。e._1._1 用于第一个水果,e._1._2 用于第二个水果。

使用 Scala 集合一段时间后,我不再喜欢 Java。:) 但当然不是每家公司都允许改变,学习它需要一段时间。

于 2012-05-09T22:47:57.997 回答