排序和重新安排HashMaps列表

时间:2010-03-16 15:02:03

标签: java collections

我有一个List>这是数据库表的直接表示。在将数据加载到HashMaps列表后,我正在尝试排序并应用一些魔法。在我的情况下,这是唯一一种硬性和快速的方法来实现它becoz我有一个规则引擎,实际上在几次计算后更新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 to toDate。

意思是,如果你考虑最后两行,他们有相同的actionId = 1234和相同的eventId = 11.现在我们可以从2月3日17:54:12的那两条记录中选择最少的fromDate,然后再到日期是3月31日星期三10:54:12并将这2条记录从日期更新到日期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();
            }
        }
    }


}

6 个答案:

答案 0 :(得分:2)

据我所知,您的所有数据都是从数据库中检索出来的。你为什么不通过SQL对事物进行排序和分组?

UPD(评论后):那我绝对喜欢

的解决方案
TreeMap<Integer, List<DbRecord>> 

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

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

更好的方法是使用Google Collections中的TreeMultimap

答案 1 :(得分:1)

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


}

答案 2 :(得分:0)

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

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

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

答案 3 :(得分:0)

听起来你真的想要每个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;
  }

}

然后你不需要创建任何额外的对象,并且将需要更少的对象进行排序(如果你需要对它们进行排序)。

答案 4 :(得分:0)

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

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种不同排序结果的点,它将会因为每种排序都会覆盖(或者至少可能会破坏)前一种。为此你可以

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

答案 5 :(得分:0)

这是我的最终解决方案 -

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


}