Сортировка и реорганизация списка HashMaps - PullRequest
0 голосов
/ 16 марта 2010

У меня есть Список>, который является прямым представлением таблицы базы данных. Я пытаюсь отсортировать и применить магию после загрузки данных в список 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. Теперь вот мой вопрос -

Для каждой группы, имеющей один и тот же идентификатор события, мне нужно обновить записи, чтобы они стали шире от даты до даты.

То есть, если вы считаете, что последние две строки имеют одинаковый actionId = 1234 и один и тот же eventId = 11. Теперь мы можем выбрать наименьшее значение fromDate из этих двух записей, то есть ср 17 марта 10:54:12 и далее toDate Ср 31 марта 10:54:12 и обновите эти 2 записи с даты и до даты Ср 17 марта 10:54:12 и Ср 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 ]

2 голосов
/ 16 марта 2010

Как я понял из вашего описания все ваши данные извлекаются из БД. Почему вы не делаете сортировку и группировку с помощью SQL?

UPD (после комментария): тогда мне определенно нравится решение с

TreeMap<Integer, List<DbRecord>> 

где actionIds - ключи этого TreeMap, а каждый элемент вашего списка - объект DbRecord.

В этом случае проблемы с сортировкой и группировкой будут решаться неявно, и вам нужно будет только выполнить итерацию по карте для обновления значений дат.

Еще лучше использовать TreeMultimap из Google Collections.

1 голос
/ 03 декабря 2010
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)); 
 }


}
0 голосов
/ 16 марта 2010

Вот мое окончательное решение -

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


}
0 голосов
/ 16 марта 2010

В ряде публикаций предлагается собственный компаратор и используется естественная сортировка, предоставляемая набором деревьев или картой дерева, например,

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 различным результатам сортировки, это будет перерыв, так как каждый вид перезаписывает (или, по крайней мере, может потенциально сломать) предыдущий. Для этого вы можете либо

  • сортировка глубоких копий карт, создание полной копии набора (ов) для каждой операции. Это может быть очень дорого, если ваши наборы данных большие.
  • вытащить карты и сгенерировать ключ для каждой. Оставьте оригинальную коллекцию карт неизменной. Для индивидуальных сортировок сравнения сортируйте ключи, ссылаясь на неизменяемый набор (т. Е. Сохраняйте данные сортировки отдельно от картографических данных)
0 голосов
/ 16 марта 2010

Похоже, вы действительно хотите иметь только один объект на пару 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;
  }

}

Тогда вам не нужно будет создавать какие-либо дополнительные объекты, и у вас будет меньше объектов для сортировки (если вам вообще потребуется их сортировать).

0 голосов
/ 16 марта 2010

Вы хотите отсортировать свой список? Затем используйте TreeSet и настраиваемый компаратор. Таким образом, каждый раз, когда карта добавляется, она будет установлена ​​в правильном положении.

Обратите внимание, что если вы хотите изменить алгоритм сортировки во время использования списка, вы можете вместо этого использовать <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html#sort(java.util.List,%20java.util.Comparator)" rel="nofollow noreferrer">Collections#sort</a>.

И, наконец, обратите внимание, что я считаю ваш способ сортировки вещей довольно странным, поскольку сортировку данных в БД обычно можно выполнить более последовательно, используя предикат SORT в вашем выражении SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...