Как использовать indexOf в Списке, содержащем HashMap с несколькими парами ключ / значение - PullRequest
1 голос
/ 26 января 2012

У меня есть List, содержащий HashMaps. Каждый HashMap в списке может содержать несколько пар key/value. Я хочу indexOf в списке, чтобы узнать индекс элемента, где передается в HashMap. Однако проблема в том, что метод e quals из HashMap при сравнении смотрит на все entrySet. Что не то, что я хочу.

Пример:

    List<HashMap> benefit = new ArrayList<HashMap>();
    HashMap map1 = new HashMap();
    map1.put("number", "1");
    benefit.add(map1);
    HashMap map2 = new HashMap();
    map2.put("number", "2");
    map2.put("somethingelse", "blahblah"); //1
    benefit.add(map2);

    HashMap find = new HashMap();
    find.put("number", "2");
    int index = benefit.indexOf(find);
    if (index >= 0)
        System.out.println(benefit.get(index).get("number"));

Приведенный выше код ничего не печатает из-за строки с //1.

  • Что мне нужно сделать, чтобы вышеприведенный код действительно печатал 2?
  • Есть ли способ реализовать сопоставимый в списке, чтобы я мог определить мой собственный?

Ответы [ 5 ]

4 голосов
/ 26 января 2012

Я думаю, что вы ищете retainAll(), так что вы можете сравнить только те элементы, которые вас интересуют:

int index = myIndexOf(benefit, find);

...

static int myIndexOf(List<HashMap> benefit, Map find) {
    int i = 0;
    for (Map map : benefit) {
        Map tmp = new HashMap(map);
        tmp.keySet().retainAll(find.keySet());
        if (tmp.equals(find)) {
            return i;
        }
        i++;
    }
    return -1;
}

Можно, конечно, объявить свой собственный подкласс List, который переопределяет метод indexOf этим поведением. Тем не менее, я не думаю, что это хорошая идея. Это нарушило бы контракт метода indexOf:

возвращает самый низкий индекс i, такой что (o == null? Get (i) == null: o.equals (get (i)))

Это может сбить с толку тех, кто поддерживает код. Затем вы можете подумать, что вы можете создать подкласс HashMap для переопределения equals, но это нарушит свойство симметрии Object.equals ().

1 голос
/ 26 января 2012

То, как вы пытаетесь достичь своей цели, неверно.Метод indexOf работает точно так же, как и в этом случае.Он пытается найти точное совпадение, а не частичное.

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

Другой способбыло бы создать прокси-класс вокруг вашего List и добавить новый метод findMapWithEntry (String key, String value), который будет выполнять этот поиск для вас (тот же поиск, который я описал выше).

0 голосов
/ 26 января 2012

Учитывая, что вы не можете изменить дизайн, поможет ли ваш собственный метод поиска?

Код ниже должен работать, если я понял, что вы пытаетесь сделать, и он работает в O (n)

public static String find(List<HashMap<String,String>> listMap, String key, String value) {
    for(int i = 0; i < listMap.size(); i++)
        if(listMap.get(i).get(key).equals(value))
            return value;

    return null;
}
0 голосов
/ 26 января 2012

Почему бы не изменить способ поиска?

List<Map> matchingBenefits = new ArrayList<Map>();
for (Map m : benefit) {
    if (m.containsKey("number") && m.get("number").equals("2"))
        matchingBenefits.add(m);
}
for (Map m : matchingBenefits) {
    System.out.println(m.get("number"));
}
0 голосов
/ 26 января 2012

Вы всегда можете переопределить метод indexOf.Посмотрите на источник для ArrayList:

   public int indexOf(Object o) {
     if (o == null) {
       for (int i = 0; i < size; i++)
         if (elementData[i]==null)
          return i;
     else {
       for (int i = 0; i < size; i++)
         if (o.equals(elementData[i]))
           return i;
     }
     return -1;
   }

Так что это совсем не очень сложный алгоритм поиска.Вы можете посмотреть на что-то вроде:

List benefit = new ArrayList(){
 public int indexOf(Object o){
      if (o == null) {
        for (int i = 0; i < size; i++)
         if (elementData[i]==null)
           return i;
      else {
        for (int i = 0; i < size; i++) //traverse the hashmaps
         Object key = ((HashMap)o).keySet().get(0); //assuming one pair
         Object val = ((HashMap)o).valueSet().get(0);
         if (
            ((HashMap)elementData[i]).containsKey(key) &&             
            ((HashMap)elementData[i]).get(key).equals(val))
              return i;
      }
      return -1;
 };

Мой совет - рассмотреть другую структуру данных, возможно, написать для нее собственную.

...