对一个Map<String, String>列表进行排序

29
我有一个像这样创建的列表变量:
List> list = new ArrayList>();
在我的Android应用程序中,该列表被填充。
仅作为一个示例:
Map<String, String> map1 = new HashMap<String, String>();
map.put("name", "Josh");
...

Map<String, String> map2 = new HashMap<String, String>();
map.put("name", "Anna");
...

Map<String, String> map3 = new HashMap<String, String>();
map.put("name", "Bernie");
...

list.add(map1);
list.add(map2);
list.add(map3);

我正在使用list通过扩展BaseAdapter并实现各种方法来在ListView中显示结果。

我的问题是:我需要基于映射的键名称按字母顺序对 list进行排序。

问题:有什么简单的方法可以根据映射的键名称按字母顺序对list进行排序?

我似乎无法理解这个问题。 我已将每个Map中的每个名称提取到一个String数组中,并进行了排序(Arrays.sort(strArray);)。但是,这并没有保留每个Map中的其他数据,因此我不太确定如何保留其他映射值。


4
@DLK,知道如何编写自定义比较器正是binnyb正在探索的内容。 - Paul McKenzie
1
@Jon Skeet和@JB Nizet的回答都正确指出,对于你的记录,Map可能是一个糟糕的选择。一个带有属性/获取器/设置器的自定义类会更好。为什么呢?1)鲁棒性/类型安全,2)内存使用,3)性能,4)代码更简单。 - Stephen C
谢谢你的建议,我会考虑改变我的设置。 - james
这是我第一次在Java编程中需要排序,除了使用SQL的order by之外。在提问之前,我已经尝试过搜索答案,但是没有找到解决我的问题的充分答案。抱歉打扰了! - james
2
@binnyb - 不用道歉。我在谷歌上搜索了这个问题的解决方案,你的问题提供了很多好的答案。作为来自不同平台的人,我不知道比较器,现在只用了几分钟就明白了。这就是StackOverflow的奇妙之处。点赞! - katzenhut
9个回答

43

以下代码完美运行

public Comparator<Map<String, String>> mapComparator = new Comparator<Map<String, String>>() {
    public int compare(Map<String, String> m1, Map<String, String> m2) {
        return m1.get("name").compareTo(m2.get("name"));
    }
}

Collections.sort(list, mapComparator);

但是你的地图应该是特定类的实例。


谢谢,这解决了问题(稍作语法修正)。我会考虑创建一个专门的类来处理列表,我之前从未想过这个。 - james
2
我不知道你在地图中存储了什么,但如果只是静态属性(姓名、名字、年龄等),那么你甚至可以用一个类来替换地图(例如:class Person {private String name; private String firstName, etc.)。 - JB Nizet

7
@Test
public void testSortedMaps() {
    Map<String, String> map1 = new HashMap<String, String>();
    map1.put("name", "Josh");

    Map<String, String> map2 = new HashMap<String, String>();
    map2.put("name", "Anna");

    Map<String, String> map3 = new HashMap<String, String>();
    map3.put("name", "Bernie");

    List<Map<String, String>> mapList = new ArrayList<Map<String, String>>();
    mapList.add(map1);
    mapList.add(map2);
    mapList.add(map3);

    Collections.sort(mapList, new Comparator<Map<String, String>>() {
        public int compare(final Map<String, String> o1, final Map<String, String> o2) {
            return o1.get("name").compareTo(o2.get("name"));
        }
    });

    Assert.assertEquals("Anna", mapList.get(0).get("name"));
    Assert.assertEquals("Bernie", mapList.get(1).get("name"));
    Assert.assertEquals("Josh", mapList.get(2).get("name"));

}

7
你应该实现一个Comparator<Map<String, String>>,它从传递给它的两个映射中提取“name”值并进行比较。
然后使用Collections.sort(list, comparator)
但是你确定Map<String, String>真的是你的列表的最佳元素类型吗?也许你应该有另一个类,其中包含一个Map<String, String>,但也有一个getName()方法?

5

如果你想使用 lambda 表达式,让代码更易读

  List<Map<String,String>> results;

  Comparator<Map<String,String>> sortByName = Comparator.comparing(x -> x.get("Name"));

  public void doSomething(){
    results.sort(sortByName)
  }

1
这个答案帮助我以更简洁的方式解决了我遇到的问题,使用了thenComparator。谢谢。 - Ronnie

4

你需要创建一个比较器。我不确定为什么每个值都需要自己的映射,但以下是比较器的样子:

class ListMapComparator implements Comparator {
    public int compare(Object obj1, Object obj2) {
         Map<String, String> test1 = (Map<String, String>) obj1;
         Map<String, String> test2 = (Map<String, String>) obj2;
         return test1.get("name").compareTo(test2.get("name"));
    }
}

您可以通过以下示例看到它的工作原理:

public class MapSort {
    public List<Map<String, String>> testMap() {
         List<Map<String, String>> list = new ArrayList<Map<String, String>>();
         Map<String, String> myMap1 = new HashMap<String, String>();
         myMap1.put("name", "Josh");
         Map<String, String> myMap2 = new HashMap<String, String>();
         myMap2.put("name", "Anna");

         Map<String, String> myMap3 = new HashMap<String, String>();
         myMap3.put("name", "Bernie");


         list.add(myMap1);
         list.add(myMap2);
         list.add(myMap3);

         return list;
    }

    public static void main(String[] args) {
         MapSort ms = new MapSort();
         List<Map<String, String>> testMap = ms.testMap();
         System.out.println("Before Sort: " + testMap);
         Collections.sort(testMap, new ListMapComparator());
         System.out.println("After Sort: " + testMap);
    }
}

由于我没有担心这些问题,所以您会收到一些类型安全警告。希望这有所帮助。


1

虽然这并不是对你问题的直接回答,但我有一个需要按照值属性排序Map列表的要求,这个方法在你的情况下同样适用:

List<Map<String, Object>> sortedListOfMaps = someListOfMaps.sorted(Comparator.comparing(map -> ((String) map.get("someKey")))).collect(Collectors.toList()))

0
try {
        java.util.Collections.sort(data,
                new Comparator<Map<String, String>>() {
                    SimpleDateFormat sdf = new SimpleDateFormat(
                            "MM/dd/yyyy");

                    public int compare(final Map<String, String> map1,
                            final Map<String, String> map2) {
                        Date date1 = null, date2 = null;
                        try {
                            date1 = sdf.parse(map1.get("Date"));
                            date2 = sdf.parse(map2.get("Date"));
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }
                        if (date1.compareTo(date2) > 0) {
                            return +1;
                        } else if (date1.compareTo(date2) == 0) {
                            return 0;
                        } else {
                            return -1;
                        }
                    }
                });

    } catch (Exception e) {

    }


0

有点跑题了
这是一个用于查看sharedpreferences的小工具
基于上面的答案
对某些人可能会有帮助

@SuppressWarnings("unused")
public void printAll() {
    Map<String, ?> prefAll = PreferenceManager
        .getDefaultSharedPreferences(context).getAll();
    if (prefAll == null) {
        return;
    }
    List<Map.Entry<String, ?>> list = new ArrayList<>();
    list.addAll(prefAll.entrySet());
    Collections.sort(list, new Comparator<Map.Entry<String, ?>>() {
        public int compare(final Map.Entry<String, ?> entry1, final Map.Entry<String, ?> entry2) {
            return entry1.getKey().compareTo(entry2.getKey());
        }
    });
    Timber.i("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
    Timber.i("Printing all sharedPreferences");
    for(Map.Entry<String, ?> entry : list) {
        Timber.i("%s: %s", entry.getKey(), entry.getValue());
    }
    Timber.i("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}

0

有很多种方法可以解决这个问题。使用Java 8中最简单的解决方法如下:

根据您的要求,按照Map键名进行字母顺序排序

第一种方式:

list = list.stream()
           .sorted((a,b)-> (a.get("name")).compareTo(b.get("name")))
           .collect(Collectors.toList());

或者,

list = list.stream()
           .sorted(Comparator.comparing(map->map.get("name")))
           .collect(Collectors.toList());

第二种方式:
Collections.sort(list, Comparator.comparing(map -> map.get("name")));

第三种方法:

list.sort(Comparator.comparing(map-> map.get("name")));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接