2014-02-24 38 views
0

我目前有一个安装程序,其中数据结构是ArrayList,每个键包含ArrayList中每个键的HashMap。我想要做的是能够通过HashMap本身内的键或键进行排序。在我的研究中,大部分的建议似乎是使用Collections.sort(ArrayList,comparatorFunction()),然后构建一个自定义的Comparator函数来完成排序,但作为一个完整的noob如何构建一个比较器...我不'甚至不知道从哪里开始,更不用说构建一个'我敢肯定不是一个简单的设置。任何碰巧知道某些资源对于解决这种功能都很有用的方法?通过嵌套的HashMap中的多个键排序

编辑:对不起,一些示例结构将有所帮助。

如果你调用了arrayList.get(0)并对它做了一个System.out.println,它会返回说{镇=多伦多,人口= 2,500,000,年龄= 147},我想要做的是有它,所以我可以说人口排序ArrayList,然后例如年龄。

+0

[如何使用比较器接口](http://stackoverflow.com/questions/16126563/how-to-use-the-comparator-interface) – mazaneicha

+2

*“一个ArrayList,每个键包含一个HashMap对于ArrayList中的每个键“* ArrayList没有键,所以......你是什么意思?你能举一个例子说明这些是如何声明的以及你想要排序的吗? – Radiodef

回答

1

通常在这种情况下,比较器的工作是简单地从其他东西返回一个比较值。例如,这里是一个比较会按字母顺序排列的字体:

class FontAlphabetizer 
implements Comparator<Font> { 
    @Override 
    public int compare(Font font1, Font font2) { 
     return font1.getName().compareTo(font2.getName()); 
    } 
} 

这实际上是非常简单的:getName返回一个字符串而我们要做的就是返回字符串的方法compareTo的价值。

在这里它看起来像你所拥有的是ArrayList<Map>,你想根据Map中的选定值对ArrayList进行排序。所以你需要的是一个Comparator<Map>。您需要为比较器提供您想要排序的相应值的关键字。这可以表示一般像下面这样:

class MapValueComparator<K, V extends Comparable<V>> 
implements Comparator<Map<K, V>> { 
    final K key; 

    MapValueComparator(K key) { 
     this.key = key; 
    } 

    @Override 
    public int compare(Map<K, V> map1, Map<K, V> map2) { 
     return map1.get(key).compareTo(map2.get(key)); 
    } 
} 

这是比较地图比较器和它在声明中指定有该地图的价值观也必须是可比的。它根据从给定密钥中检索的值进行比较。

因此,举例来说,如果我们有一个ArrayList<Map<String, String>>,我们可以通过值从"town"排序是这样的:

static void sortByTown(List<Map<String, String>> list) { 
    Collections.sort(list, new MapValueComparator<String, String>("town")); 
} 

,打嗝是,你说你有town=Toronto, population=2,500,000这表明人口要排序是一个字符串(因为它可能与多伦多在相同的地图中)。作为字符串可能是不希望的,因为它会按字典顺序排序(50进入250万之后,因为5自带2后)比较人口。在这种情况下通用版本可能无法工作,因为你需要采取的值转换为数字的一个额外的步骤。

class PopulationComparator 
implements Comparator<Map<String, String>> { 
    @Override 
    public int compare(Map<String, String> map1, Map<String, String> map2) { 
     final Long pop1 = Long.valueOf(map1.get("population")); 
     final Long pop2 = Long.valueOf(map2.get("population")); 

     return pop1.compareTo(pop2); 
    } 
} 

(而作为一个侧面说明,如果你的群体包括你需要它解析为数字前将其格式化。您可以使用replaceAll("\\D", "")从字符串中删除所有非数字的逗号。)

这也是一种情况,为此创建一个类而不是使用Map可能会有好处。那么你可以让数字字段为数字类型。如果你有一堂课,比较将大致相同,只是返回一个选定字段的比较。

1

自定义比较器可用于定义您的类的对象可以比较的方式。它的语法如下:

public class CustomComparator implements Comparator<MyObjectType> 
{ 
    public int compare(MyObjectType ob1 , MyObjectType ob2) 
    { 
    //code to compare the 2 objects 
    } 
} 

请参考以下链接的信息,在收集要素的自定义排序创建一个比较类:link

1

这里是你在找什么:

final List<Map<String, Object>> towns = new ArrayList<Map<String, Object>>(); 

final Map<String, Object> toronto = new HashMap<String, Object>(); 
toronto.put("town", "Toronto"); 
toronto.put("population", 2500000); 
toronto.put("age", 147); 
towns.add(toronto); 

final Map<String, Object> ottawa = new HashMap<String, Object>(); 
ottawa.put("town", "Ottawa"); 
ottawa.put("population", 883000); 
ottawa.put("age", 159); 
towns.add(ottawa); 

final Map<String, Object> montreal = new HashMap<String, Object>(); 
montreal.put("town", "Montreal"); 
montreal.put("population", 1600000); 
montreal.put("age", 372); 
towns.add(montreal); 

final Map<String, Object> quebec = new HashMap<String, Object>(); 
quebec.put("town", "Quebec City"); 
quebec.put("population", 600000); 
quebec.put("age", 406); 
towns.add(quebec); 

final Map<String, Object> vancouver = new HashMap<String, Object>(); 
vancouver.put("town", "Vancouver"); 
vancouver.put("population", 600000); 
vancouver.put("age", 128); 
towns.add(vancouver); 

Collections.sort(towns, new Comparator<Map<String, Object>>() { 
    @Override 
    public int compare(final Map<String, Object> o1, final Map<String, Object> o2) { 
     if (o1.get("population") instanceof Integer && o2.get("population") instanceof Integer && !((Integer)o1.get("population")).equals((Integer)o2.get("population"))) { 
      return ((Integer)o1.get("population")).compareTo((Integer)o2.get("population")); 
     } 
     if (o1.get("age") instanceof Integer && o2.get("age") instanceof Integer) { 
      return ((Integer)o1.get("age")).compareTo((Integer)o2.get("age")); 
     } 
     // Default if there is no population/no age, shouldn't happen. 
     // TODO : do something else. 
     return o1.toString().compareTo(o2.toString()); 
    } 
}); 

for (final Map<String, Object> town: towns) { 
    System.out.println(town.get("population")+"\t"+town.get("age")+"\t"+town.get("town")); 
} 

代码的第一部分是根据您所说的创建ArrayList,然后我们使用自定义ComparatorList进行排序,并打印结果。

这里是输出:

600000 128 Vancouver 
600000 406 Quebec City 
883000 159 Ottawa 
1600000 372 Montreal 
2500000 147 Toronto 

正如你所看到的,它是由人口排序,然后按年龄。

但是,也许是最好的解决办法是创建一个对象Town,有三个字段(name,​​和age),并使用这个对象,而不是HashMap秒。