简体   繁体   English

如何按地图中键的某些属性对地图进行排序?

[英]How can I sort a Map by some property of the key in the map?

Lets say we have a class called Activity: 假设我们有一个叫做Activity的类:

public class Activity {
    private Project project;
}

So every Activity Object will have a Project.. Also every Project has a Unit. 因此,每个活动对象都将有一个项目。每个项目也都有一个单元。 Two different Projects can have the same unit: 两个不同的项目可以具有相同的单元:

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

And a Unit has a name as well: 单位也有一个名称:

public class Unit {
    private String unitName;
}

So currently I have a TreeMap like this: 所以目前我有一个像这样的TreeMap:

SortedMap<Project,List<Activity> myMap

One example may be: 一个示例可能是:

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

etc... 等等...

Now lets assume projectOne has the same unit with projectThree (unitAAA) and projectTwo has unitZZZ... 现在假设projectOne与projectThree(unitAAA)具有相同的单位,而projectTwo具有unitZZZ ...

I want to sort my Map alphabetically by the unit of the project elements: 我想按项目元素的单位字母顺序对地图进行排序:

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

How can I achieve this? 我该如何实现? I know in Stackoverflow the question is What have you tried so far? 我知道在Stackoverflow中,问题是您到目前为止尝试了什么? , well I am really stuck in this point so I have not really tried anything besides trying to come up with what I can even try.. ,好吧,我确实停留在这一点上,因此除了尝试提出我可以尝试的方法以外,我还没有尝试过其他任何方法。

A map is basically an unsorted collection but there are sorted maps as well, eg TreeMap . 映射基本上是未排序的集合,但是也有排序的映射,例如TreeMap In that case provide a comparator which sorts projects based on their to the constructor: 在这种情况下,请提供一个比较器,该比较器根据项目对构造函数的排序:

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

Note that if you need to sort the map using a different comparator (or can't provide a comparator) you'd have to create a list using the entries of the map and sort that. 请注意,如果您需要使用其他比较器(或无法提供比较器)对地图进行排序,则必须使用地图的条目创建一个列表并将其排序。

Something like this: 像这样:

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

Also note that it is not possible for a collection or sorted map to have different sort orders, ie you can only provide one comparator or natural ordering for the elements. 另请注意,集合或排序映射不可能具有不同的排序顺序,即,您只能为元素提供一个比较器或自然排序。

In any case you'd either have to change the sort order of the collection (eg by using Collections.sort(...) or, if you need to maintain multiple orders simultanously, use multiple collections (which can be sorted views to a base collection/map). 在任何情况下,您要么必须更改集合的排序顺序(例如,通过使用Collections.sort(...)要么如果您需要同时维护多个顺序,请使用多个集合(可以将视图排序为一个集合)基本收藏/地图)。

Update I'll add an example for a copy of the TreeMap : 更新我将为TreeMap的副本添加一个示例:

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

Update 2 更新2

As for the comparator, note that it is required to be consistent with equals , ie the comparator must only return 0 if both objects are equal. 对于比较器,请注意必须与equals保持一致 ,即,如果两个对象相等 ,则比较器必须仅返回0。 Thus you'd need to take other properties of a Project into account if the units are equal. 因此,如果单位相等,则需要考虑Project其他属性。 Without that, if two projects use the same unit, they are considered equal by the TreeMap and thus entries might get lost. 否则,如果两个项目使用相同的单位,则TreeMap会将它们视为相等,因此条目可能会丢失。

For more information see: What does comparison being consistent with equals mean ? 有关更多信息,请参见: 比较等于等号意味着什么? What can possibly happen if my class doesn't follow this principle? 如果我的课堂不遵循这一原则,可能会发生什么?

The compare method might look like this, if the project names are unique: 如果项目名称是唯一的,则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;
}

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM