简体   繁体   English

排序和重新排列HashMap列表

[英]Sorting and Re-arranging List of HashMaps

I have a List> which is straight forward representation of a database table. 我有一个List>,它是数据库表的直接表示。 I am trying to sort and apply some magic after the data is loaded into List of HashMaps. 我正在尝试将数据加载到HashMaps列表中后进行排序并应用一些魔术。 In my case this is the only hard and fast way of doing it becoz I have a rules engine that actually updates the values in the HashMap after several computations. 就我而言,这是唯一的快捷方法,因为我有一个规则引擎,该引擎实际上是在几次计算后更新HashMap中的值的。

Here is a sample data representation of the HashMap (List of HashMap) - 这是HashMap的示例数据表示形式(HashMap的列表)-

{fromDate=Wed Mar 17 10:54:12 EDT 2010, eventId=21, toDate=Tue Mar 23 10:54:12 EDT 2010, actionId=1234}
{fromDate=Wed Mar 17 10:54:12 EDT 2010, eventId=11, toDate=Wed Mar 17 10:54:12 EDT 2010, actionId=456}
{fromDate=Sat Mar 20 10:54:12 EDT 2010, eventId=20, toDate=Thu Apr 01 10:54:12 EDT 2010, actionId=1234}
{fromDate=Wed Mar 24 10:54:12 EDT 2010, eventId=22, toDate=Sat Mar 27 10:54:12 EDT 2010, actionId=1234}
{fromDate=Wed Mar 17 10:54:12 EDT 2010, eventId=11, toDate=Fri Mar 26 10:54:12 EDT 2010, actionId=1234}
{fromDate=Sat Mar 20 10:54:12 EDT 2010, eventId=11, toDate=Wed Mar 31 10:54:12 EDT 2010, actionId=1234}
{fromDate=Mon Mar 15 10:54:12 EDT 2010, eventId=12, toDate=Wed Mar 17 10:54:12 EDT 2010, actionId=567}

I am trying to achieve couple of things - 我正在尝试达成几项目标-

1) Sort the list by actionId and eventId after which the data would look like - 1)按actionId和eventId对列表进行排序,之后数据看起来像-

{fromDate=Wed Mar 17 10:54:12 EDT 2010, eventId=11, toDate=Wed Mar 17 10:54:12 EDT 2010, actionId=456}
{fromDate=Mon Mar 15 10:54:12 EDT 2010, eventId=12, toDate=Wed Mar 17 10:54:12 EDT 2010, actionId=567}
{fromDate=Wed Mar 24 10:54:12 EDT 2010, eventId=22, toDate=Sat Mar 27 10:54:12 EDT 2010, actionId=1234}
{fromDate=Wed Mar 17 10:54:12 EDT 2010, eventId=21, toDate=Tue Mar 23 10:54:12 EDT 2010, actionId=1234}
{fromDate=Sat Mar 20 10:54:12 EDT 2010, eventId=20, toDate=Thu Apr 01 10:54:12 EDT 2010, actionId=1234}
{fromDate=Wed Mar 17 10:54:12 EDT 2010, eventId=11, toDate=Fri Mar 26 10:54:12 EDT 2010, actionId=1234}
{fromDate=Sat Mar 20 10:54:12 EDT 2010, eventId=11, toDate=Wed Mar 31 10:54:12 EDT 2010, actionId=1234}

2) If we group the above list by actionId they would be resolved into 3 groups - actionId=1234, actionId=567 and actionId=456. 2)如果将以上列表按actionId分组,则将它们分为3组-actionId = 1234,actionId = 567和actionId = 456。 Now here is my question - 现在这是我的问题-

For each group having the same eventId, I need to update the records so that they have wider fromDate to toDate. 对于每个具有相同eventId的组,我需要更新记录,以使它们的fromDate到toDate的范围更广。

Meaning, if you consider the last two rows they have same actionId = 1234 and same eventId = 11. Now we can to pick the least fromDate from those 2 records which is Wed Mar 17 10:54:12 and farther toDate which is Wed Mar 31 10:54:12 and update those 2 record's fromDate and toDate to Wed Mar 17 10:54:12 and Wed Mar 31 10:54:12 respectively. 意思是,如果您考虑最后两行,则它们具有相同的actionId = 1234和相同的eventId =11。现在,我们可以从这2条记录中选择最少的fromDate,即Wed Mar 17 10:54:12,再选择toDate,即Wed Mar 31 10:54:12并将这两个记录的fromDate和toDate更新到3月17日星期三10:54:12和3月31日星期三10:54:12。

Any ideas? 有任何想法吗?

PS: I already have some pseudo code to start with. PS:我已经有一些伪代码开始了。

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.lang.builder.CompareToBuilder;
public class Tester {
    boolean ascending = true ;
    boolean sortInstrumentIdAsc = true ;
    boolean sortEventTypeIdAsc = true ; 

    public static void main(String args[]) {
        Tester tester = new Tester() ;
        tester.printValues() ;
    }

    public void printValues ()
    {

        List<HashMap<String,Object>> list = new ArrayList<HashMap<String,Object>>() ;
        HashMap<String,Object> map = new HashMap<String,Object>();

        map.put("actionId", new Integer(1234)) ;
        map.put("eventId", new Integer(21)) ;
        map.put("fromDate", getDate(1) ) ;
        map.put("toDate", getDate(7) ) ;
        list.add(map);

        map = new HashMap<String,Object>();
        map.put("actionId", new Integer(456)) ;
        map.put("eventId", new Integer(11)) ;
        map.put("fromDate", getDate(1)) ;
        map.put("toDate", getDate(1) ) ;
        list.add(map);


        map = new HashMap<String,Object>();
        map.put("actionId", new Integer(1234)) ;
        map.put("eventId", new Integer(20)) ;
        map.put("fromDate", getDate(4) ) ;
        map.put("toDate", getDate(16) ) ;
        list.add(map);

        map = new HashMap<String,Object>();
        map.put("actionId", new Integer(1234)) ;
        map.put("eventId", new Integer(22)) ;
        map.put("fromDate",getDate(8) ) ;
        map.put("toDate", getDate(11)) ;
        list.add(map);


        map = new HashMap<String,Object>();
        map.put("actionId", new Integer(1234)) ;
        map.put("eventId", new Integer(11)) ;
        map.put("fromDate",getDate(1) ) ;
        map.put("toDate", getDate(10) ) ;
        list.add(map);

        map = new HashMap<String,Object>();
        map.put("actionId", new Integer(1234)) ;
        map.put("eventId", new Integer(11)) ;
        map.put("fromDate",getDate(4) ) ;
        map.put("toDate", getDate(15) ) ;
        list.add(map);


        map = new HashMap<String,Object>();
        map.put("actionId", new Integer(567)) ;
        map.put("eventId", new Integer(12)) ;
        map.put("fromDate", getDate(-1) ) ;
        map.put("toDate",getDate(1)) ;
        list.add(map);


        System.out.println("\n Before Sorting \n ");
        for(int j = 0 ; j < list.size() ; j ++ ) 
            System.out.println(list.get(j));    

        Collections.sort ( list , new HashMapComparator2 () ) ;

        System.out.println("\n After Sorting \n ");
        for(int j = 0 ; j < list.size() ; j ++ ) 
            System.out.println(list.get(j));

    }


    public static Date getDate(int days) {

        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.add(Calendar.DATE, days);
        return cal.getTime() ;        

    }

    public class HashMapComparator2 implements Comparator
    {
        public int compare ( Object object1 , Object object2 )
        {
            if ( ascending == true )
            {
                return new CompareToBuilder()
                .append(( ( HashMap ) object1 ).get ( "actionId" ), ( ( HashMap ) object2 ).get ( "actionId" ))
                .append(( ( HashMap ) object2 ).get ( "eventId" ), ( ( HashMap ) object1 ).get ( "eventId" ))
                .toComparison();
            }
            else
            {
                return new CompareToBuilder()
                .append(( ( HashMap ) object2 ).get ( "actionId" ), ( ( HashMap ) object1 ).get ( "actionId" ))
                .append(( ( HashMap ) object2 ).get ( "eventId" ), ( ( HashMap ) object1 ).get ( "eventId" ))
                .toComparison();
            }
        }
    }


}

As I understand from your description all your data is retrieved from DB. 据我了解,从您的描述中,所有数据都是从DB检索的。 Why don't you do sorting and grouping stuff by means of SQL? 为什么不通过SQL进行排序和分组呢?

UPD (after comment): then I definitely like a solution with UPD(评论后):那么我绝对喜欢以下解决方案

TreeMap<Integer, List<DbRecord>> 

where actionIds are keys of this TreeMap and each item of your list is DbRecord object. 其中actionIds是此TreeMap的键,列表的每个项目都是DbRecord对象。

In this case sorting and grouping problems will be solved implicitly, and you'll have only to iterate through the map in order to update dates values. 在这种情况下,排序和分组问题将被隐式解决,并且您仅需遍历地图即可更新日期值。

Even better approach is to use TreeMultimap from Google Collections. 更好的方法是使用Google收藏夹中的TreeMultimap

import java.util.*;


public class hasmap {

 public static void main(String[] args) {
  List <Map> result=new ArrayList();
  Map emp1 = new HashMap();
  emp1.put("Name", "wivek");
  emp1.put("EmpID", Long.valueOf("1077"));
  emp1.put("JoinDate",new Date());
  emp1.put("MobileNo",Long.valueOf("1234567890"));

  Map emp2 = new HashMap();
  emp2.put("Name", "aww");
  emp2.put("EmpID", Long.valueOf("10"));
  emp2.put("JoinDate",new Date());
  emp2.put("MobileNo",Long.valueOf("1234567890"));

  Map emp3 = new HashMap();
  emp3.put("Name", "bww");
  emp3.put("EmpID", Long.valueOf("10"));
  emp3.put("JoinDate",new Date());
  emp3.put("MobileNo",Long.valueOf("1234567890"));

  result.add(emp1);
  result.add(emp2);
  result.add(emp3);

  System.out.println("\n Before Sorting \n" );
               for(int j = 0 ; j < result.size() ; j ++ ) 
                      System.out.println(result.get(j)); 
                srt(result,"Name");

 }

private static void srt(List<Map> result, final String n) {


  Collections.sort(result, new Comparator(){

            public int compare(Object o1, Object o2) {
             Map e1 = (Map) o1;
                Map e2 = (Map) o2;
                return e1.get(n).toString().compareToIgnoreCase(e2.get(n).toString());
            }
        });
  System.out.println("\n After Sorting \n" );
        for(int j = 0 ; j < result.size() ; j ++ ) 
            System.out.println(result.get(j)); 
 }


}

You want to sort your list ? 您想对列表进行排序? Then use a TreeSet and a customized Comparator. 然后使用TreeSet和自定义的Comparator。 This way, each time a Map is added, it will be set at the correct position. 这样,每次添加地图时,都会将其设置在正确的位置。

Notice that, if you want to change sort algorithm during list usage, you can instead use Collections#sort . 请注意,如果要在使用列表期间更改排序算法,可以改用Collections#sort

And finally notice I consider your way of sorting things quite weird, since sorting your DB data can usually be done more consistently by using a SORT predicate in your SQL statement. 最后,请注意,我认为您的排序方式很奇怪,因为通过在SQL语句中使用SORT谓词通常可以更一致地完成对DB数据的排序。

It sounds like you really want to just have one object per actionId/ eventId pair. 听起来您真的想每个actionId / eventId对只有一个对象。 Have you considered instead using something like a factory to generate a new object / modify an existing object? 您是否考虑过使用工厂之类的东西来生成新对象/修改现有对象? Rough code: 粗糙的代码:

public class ObjectFactory{

  class Key{
    String eventId, actionId;
  }

  HashMap<Key, ObjectXYZ> objects = new HashMap<...,...>();

  ObjectXYZ getObject(String actionId, String eventId, Date from, Date to){
    Key k = new Key(actionId, eventId);
    ObjectXYZ ret = objects.get(k);
    if(ret == null){
      ret = new ObjectXYZ(actionid, eventId, from, to);
      objects.put(k, ret);
    }else{
      if(from < ret.from)  ret.from = from;
      if(to < ret.to) ret.to = to;
    }
    return ret;
  }

}

Then you would not need to create any extra objects and would have fewer objects to sort (if you would need to sort them at all). 这样,您将不需要创建任何额外的对象,并且可以减少排序的对象(如果您需要对它们进行排序)。

A number of posts suggest a Custom Comparator and using natural sorting provided by a treeset or treemap, eg 许多帖子建议使用“自定义比较器”,并使用树集或树图提供的自然排序,例如

public class MapComparator implements Comparator<Map>{
   public MapComparator(String key, boolean asc){..set value properties ...}
   public int comparae(Map a, Map b) { ... compare a.get(key), b.get(key) ... }
}

Since your data is also changing on the fly, I think you have an additional complication, in that reordering your collection of maps for one operation may invalidate the ordering for a previous operation. 由于您的数据也在动态变化,因此我认为您还有其他麻烦,因为对一个操作的地图集合重新排序可能会使上一个操作的排序无效。 If you're doing operations serially, and once you've done a sort you don't need to preserve the values, that's fine, but if there's ever any point where you'll simultaneously need the access to 2 different sort results it will break, since each sort overwrites (or at least can potentially break) the previous. 如果您是串行进行操作,并且完成排序后就不需要保留值,那很好,但是如果有任何时候您同时需要访问2种不同的排序结果,它将中断,因为每种排序都会覆盖(或至少可能破坏)先前的排序。 For that you could either 为此,您可以

  • sort deep copies of the maps, create a complete copy of the set(s) for each operation. 对地图的深层副本进行排序,为每个操作创建集合的完整副本。 This could get really expensive if your data sets are large. 如果您的数据集很大,这可能会变得非常昂贵。
  • pull in the maps and generate a key for each. 拉入地图并为每个地图生成一个密钥。 Leave the original collection of maps as immutable. 将原始地图集保留为不变。 For your individual comparison sorts, sort the keys, reference the immutable collection( ie maintain the sort data separately from the map data) 对于您的单个比较排序,对键进行排序,引用不可变的集合(即,将排序数据与地图数据分开维护)

Here is my final solution - 这是我的最终解决方案-

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.lang.builder.CompareToBuilder;

public class Tester {

    boolean ascending = true ;


    boolean sortInstrumentIdAsc = true ;
    boolean sortEventTypeIdAsc = true ; 


    public static void main(String args[]) {
        Tester tester = new Tester() ;
        tester.printValues() ;
    }

    public void printValues() {

        List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
        HashMap<String, Object> map = new HashMap<String, Object>();

        map.put("actionId", new Integer(1234));
        map.put("eventId", new Integer(21));
        map.put("fromDate", getDate(1));
        map.put("toDate", getDate(7));
        list.add(map);

        map = new HashMap<String, Object>();
        map.put("actionId", new Integer(456));
        map.put("eventId", new Integer(11));
        map.put("fromDate", getDate(1));
        map.put("toDate", getDate(1));
        list.add(map);


        map = new HashMap<String, Object>();
        map.put("actionId", new Integer(1234));
        map.put("eventId", new Integer(20));
        map.put("fromDate", getDate(4));
        map.put("toDate", getDate(16));
        list.add(map);

        map = new HashMap<String, Object>();
        map.put("actionId", new Integer(1234));
        map.put("eventId", new Integer(22));
        map.put("fromDate", getDate(8));
        map.put("toDate", getDate(11));
        list.add(map);


        map = new HashMap<String, Object>();
        map.put("actionId", new Integer(1234));
        map.put("eventId", new Integer(11));
        map.put("fromDate", getDate(1));
        map.put("toDate", getDate(10));
        list.add(map);

        map = new HashMap<String, Object>();
        map.put("actionId", new Integer(1234));
        map.put("eventId", new Integer(11));
        map.put("fromDate", getDate(4));
        map.put("toDate", getDate(15));
        list.add(map);


        map = new HashMap<String, Object>();
        map.put("actionId", new Integer(1234));
        map.put("eventId", new Integer(11));
        map.put("fromDate", getDate(8));
        map.put("toDate", getDate(30));
        list.add(map);

        map = new HashMap<String, Object>();
        map.put("actionId", new Integer(567));
        map.put("eventId", new Integer(12));
        map.put("fromDate", getDate(-1));
        map.put("toDate", getDate(1));
        list.add(map);


        System.out.println("\n Before Sorting \n ");
        for (int j = 0; j < list.size(); j++) {
              System.out.println(list.get(j));
        }

        // sort the list
        HashMapComparator2 comparator = new HashMapComparator2();
        Collections.sort(list, comparator);

        System.out.println("\n After Sorting \n ");
        for (int j = 0; j < list.size(); j++) {
              System.out.println(list.get(j));
        }


        HashMap<String, Object> prev = null;
        List<HashMap<String, Object>> same = new ArrayList<HashMap<String, Object>>();
        for (HashMap<String, Object> row : list) {
              if (prev != null) {
                    int diff = comparator.compare(prev, row);
                    if (diff == 0) {
                          same.add(row);
                          same.add(prev);
                    }
                    else {
                          merge(same);
                          same.clear();
                    }
              }
              prev = row;
        }
        merge(same);

        System.out.println("\n After Merging \n ");
        for (int j = 0; j < list.size(); j++) {
              System.out.println(list.get(j));
        }
  }

  private void merge(List<HashMap<String, Object>> same) {
        if (!same.isEmpty()) {
              // Now find min max
              Date min = null;
              Date max = null;
              for (HashMap<String, Object> i : same) {
                    Date from = (Date) i.get("fromDate");
                    Date to = (Date) i.get("toDate");
                    if (min == null) {
                          min = from;
                    }
                    else if (from.before(min)) {
                          min = from;
                    }
                    if (max == null) {
                          max = to;
                    }
                    else if (to.after(max)) {
                          max = to;
                    }
              }
              for (HashMap<String, Object> i : same) {
                    i.put("fromDate", min);
                    i.put("toDate", max);
              }
        }
  }


    public static Date getDate(int days) {

        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.add(Calendar.DATE, days);
        return cal.getTime() ;        

    }

    public class HashMapComparator2 implements Comparator
    {
        public int compare ( Object object1 , Object object2 )
        {
            if ( ascending == true )
            {
                return new CompareToBuilder()
                .append(( ( HashMap ) object1 ).get ( "actionId" ), ( ( HashMap ) object2 ).get ( "actionId" ))
                .append(( ( HashMap ) object2 ).get ( "eventId" ), ( ( HashMap ) object1 ).get ( "eventId" ))
                .toComparison();
            }
            else
            {
                return new CompareToBuilder()
                .append(( ( HashMap ) object2 ).get ( "actionId" ), ( ( HashMap ) object1 ).get ( "actionId" ))
                .append(( ( HashMap ) object2 ).get ( "eventId" ), ( ( HashMap ) object1 ).get ( "eventId" ))
                .toComparison();
            }
        }
    }


}

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

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