【问题标题】:How can I sort a Map by some property of the key in the map?如何通过地图中键的某些属性对地图进行排序?
【发布时间】:2014-03-04 11:47:40
【问题描述】:

假设我们有一个名为 Activity 的类:

public class Activity {
    private Project project;
}

所以每个活动对象都会有一个项目。每个项目都有一个单元。两个不同的项目可以有相同的单位:

public class Project {
    private String projectName; 
    private Unit unit;
}

单位也有名称:

public class Unit {
    private String unitName;
}

所以目前我有一个这样的 TreeMap:

SortedMap<Project,List<Activity> myMap

一个例子可能是:

projectOne -> [activityOne,activityTwo,activityThree]
projectTwo -> [activityThree,activityFouractivityFive]
projectThree -> [activityFour,activityFive,activitySix]

等等……

现在假设 projectOne 与 projectThree (unitAAA) 具有相同的单元,而 projectTwo 具有 unitZZZ...

我想按项目元素单位的字母顺序对我的地图进行排序:

projectOne -> [...]
projectThree -> [...] 
projectTwo -> [...]

我怎样才能做到这一点?我知道在 Stackoverflow 中的问题是到目前为止你尝试过什么?,我真的被困在这一点上,所以除了尝试想出我什至可以尝试的东西之外,我没有真正尝试过任何东西..

【问题讨论】:

    标签: java sorting map


    【解决方案1】:

    地图基本上是一个未排序的集合,但也有排序的地图,例如TreeMap。在这种情况下,提供一个比较器,它根据项目对构造函数进行排序:

    SortedMap<Project, List<Activity>> myMap = new TreeMap<>( new Comparator<Project>() {
      public int compare( Project lhs, Project rhs) {
    
        int r = lhs.unit.unitName.compareTo(rhs.unit.unitName); //note that null checks etc. are omitted for simplicity, don't forget them in your code unless you know for sure that unit and unitName can't be null   
        if( r == 0 && !lhs.equals(rhs)) {
          //take other properties into account for consistent behavior with equals()
          //see "Update 2" below
        }
        return r;
      }
    });
    

    请注意,如果您需要使用不同的比较器(或无法提供比较器)对地图进行排序,则必须使用地图的条目创建一个列表并对其进行排序。

    类似这样的:

     List<Map.Entry<Project, List<Activity>> l = new ArrayList<>(myMap.entrySet());
     Collections.sort(l, new Comparator<Map.Entry<Project, List<Activity>>() {
       public int compare( Map.Entry<Project, List<Activity> lhs, Map.Entry<Project, List<Activity> rhs) {
        return lhs.getKey().unit.unitName.compareTo(rhs.getKey().unit.unitName);
      }
     });
    

    另请注意,集合或排序映射不可能有不同的排序顺序,即您只能为元素提供一个比较器或自然排序。

    在任何情况下,您都必须更改集合的排序顺序(例如,通过使用 Collections.sort(...) 或者,如果您需要同时维护多个顺序,请使用多个集合(可以将视图排序到基础集合/地图)。

    更新我将为TreeMap的副本添加一个示例:

    //new TreeMap like above
    SortedMap<Project, List<Activity>> copy = new TreeMap<>( new Comparator<Project>() { ... } );
    copy.putAll( myMap );
    

    更新 2

    至于比较器,注意它必须与equals一致,即比较器必须只有在两个对象相等时才返回0。因此,如果单位相等,您需要考虑 Project 的其他属性。否则,如果两个项目使用相同的单位,TreeMap 会认为它们相等,因此条目可能会丢失。

    欲了解更多信息,请参阅:What does comparison being consistent with equals mean ? What can possibly happen if my class doesn't follow this principle?

    如果项目名称是唯一的,比较方法可能如下所示:

    public int compare( Project lhs, Project rhs) {
      //as above null checks etc. are omitted for simplicity's sake
      int r = lhs.unit.unitName.compareTo(rhs.unit.unitName);
      if( r == 0 && !lhs.equals(rhs)) {
        r = lhs.projectName.compareTo( rhs.projectName );
    
        //you could also use the natural ordering of the projects here:
        //r = lhs.compareTo( rhs );
      }
      return r;
    }
    

    【讨论】:

    • 是的,抱歉,它已经是 TreeMap。但是我该如何进行转换呢?
    • @KorayTugay 通过在类Project 中正确实现compareTo,在创建TreeMap 时传递Comparator
    • @A4L 树图是从在许多其他地方使用的方法返回的。我不能将比较器传递给它。我只有数据结构,必须自己修改。
    • @KorayTugay 所以你需要和nr一起去。 1,即实现compareTo,在这种情况下,无论谁放置Project的对象,它都会按照您想要的方式进行排序。如果您不希望这种情况发生或不能这样做,因为您可以更改任何类,那么您可以考虑复制到一个新的 TreeMap 中,您可以在其中传递 Comparator
    • @KorayTugay,然后在 Project 类中添加比较逻辑,使其实现 Comparable 并覆盖其中的 'compareTo(Project o)'。
    【解决方案2】:

    无法对HashMap 进行排序,但如果要显示已排序的地图内容,可以按单元对项目列表进行排序(在Project 上查找Comparator)并获取地图上对应项目的价值。

    【讨论】:

    • 抱歉,这是一个 SortedMap。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-04
    • 1970-01-01
    • 2012-04-13
    • 2015-11-07
    • 1970-01-01
    • 1970-01-01
    • 2021-09-13
    相关资源
    最近更新 更多