如何通过地图中某个键的属性对地图进行排序?

时间:2014-03-04 11:47:40

标签: java sorting map

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

public class Activity {
    private Project project;
}

所以每个Activity对象都有一个Project ..每个Project都有一个Unit。两个不同的项目可以拥有相同的单元:

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中的问题是你到目前为止尝试了什么?,我真的陷入了这一点,所以除了试图想出我甚至可以尝试之外我还没有尝试过任何东西。

2 个答案:

答案 0 :(得分:4)

地图基本上是一个未分类的集合,但也有分类的地图,例如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?

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

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;
}

答案 1 :(得分:1)

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