繁体   English   中英

排序和重新排列HashMap列表

[英]Sorting and Re-arranging List of HashMaps

我有一个List>,它是数据库表的直接表示。 我正在尝试将数据加载到HashMaps列表中后进行排序并应用一些魔术。 就我而言,这是唯一的快捷方法,因为我有一个规则引擎,该引擎实际上是在几次计算后更新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}

我正在尝试达成几项目标-

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)如果将以上列表按actionId分组,则将它们分为3组-actionId = 1234,actionId = 567和actionId = 456。 现在这是我的问题-

对于每个具有相同eventId的组,我需要更新记录,以使它们的fromDate到toDate的范围更广。

意思是,如果您考虑最后两行,则它们具有相同的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。

有任何想法吗?

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


}

据我了解,从您的描述中,所有数据都是从DB检索的。 为什么不通过SQL进行排序和分组呢?

UPD(评论后):那么我绝对喜欢以下解决方案

TreeMap<Integer, List<DbRecord>> 

其中actionIds是此TreeMap的键,列表的每个项目都是DbRecord对象。

在这种情况下,排序和分组问题将被隐式解决,并且您仅需遍历地图即可更新日期值。

更好的方法是使用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)); 
 }


}

您想对列表进行排序? 然后使用TreeSet和自定义的Comparator。 这样,每次添加地图时,都会将其设置在正确的位置。

请注意,如果要在使用列表期间更改排序算法,可以改用Collections#sort

最后,请注意,我认为您的排序方式很奇怪,因为通过在SQL语句中使用SORT谓词通常可以更一致地完成对DB数据的排序。

听起来您真的想每个actionId / eventId对只有一个对象。 您是否考虑过使用工厂之类的东西来生成新对象/修改现有对象? 粗糙的代码:

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

}

这样,您将不需要创建任何额外的对象,并且可以减少排序的对象(如果您需要对它们进行排序)。

许多帖子建议使用“自定义比较器”,并使用树集或树图提供的自然排序,例如

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

由于您的数据也在动态变化,因此我认为您还有其他麻烦,因为对一个操作的地图集合重新排序可能会使上一个操作的排序无效。 如果您是串行进行操作,并且完成排序后就不需要保留值,那很好,但是如果有任何时候您同时需要访问2种不同的排序结果,它将中断,因为每种排序都会覆盖(或至少可能破坏)先前的排序。 为此,您可以

  • 对地图的深层副本进行排序,为每个操作创建集合的完整副本。 如果您的数据集很大,这可能会变得非常昂贵。
  • 拉入地图并为每个地图生成一个密钥。 将原始地图集保留为不变。 对于您的单个比较排序,对键进行排序,引用不可变的集合(即,将排序数据与地图数据分开维护)

这是我的最终解决方案-

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