2012-06-27 79 views
1

我需要你一些示例代码的帮助来解决我无法解脱的情况。 我有一个简单的对象列表。我的阶级是这样的:如何从Java ArrayList中删除重复的对象?

class MyClass { 
    String str; 
    Integer intgr; 
} 

而且列表包含相同的元素:

[{a1 5}, {b2 3}, {g1 1}, {b5 1}, {c9 11}, {g2 3}, {d1 4}, {b3 19}... ... ...] 

我需要检查,如果任何元素包含字符串相同的前缀(这里后缀是最后一个字符),然后保留整数中具有较大值的元素。以上示例列表的预期输出将为:

[{a1 5}, {c9 11}, {g2 3}, {d1 4}, {b3 19}... ... ...] 

字符串将具有唯一值,但可以在前缀中匹配。在java中我不太好。那么有人能帮我解决这个问题吗?这是我想要的代码,但得到IndexOutOfBoundsException。此代码有问题,所以需要您的帮助。

谢谢!

 int size = list.size(); 
     for (int j = 0; j < size; j++) { 
     if (list.get(j).str.substring(0, list.get(j).str.length()-1).compareTo(list.get(j+1).str.substring(0, list.get(j+1).str.length()-1)) == 0) { 
      if (list.get(j).intgr > list.get(j+1).intgr) 
       list.remove(list.get(j+1)); 
       size--; 
      else { 
       list.remove(list.get(j)); 
       j--; 
       size--; 
      } 
     } 
    } 
+1

一个建议我给你:不是链接这样的方法,尽量只做一个时间和他们读入临时变量。看到你的程序的逻辑错误会容易得多。 – Charles

回答

0

您的代码有两个问题。首先,当j == size - 1(最后一次迭代)时,您正在调用list.get(j + 1),这是导致异常的原因。只要将您的循环条件更改为j < size - 1并且例外情况应该消失。(或者,从j = 1开始,并与之前的元素进行比较。)

其次,您只比较每个元素及其直接后继元素。从你的描述来看,这听起来不像你想要做的那样。

我建议在单独的方法中捕获比较的逻辑。这可能是MyClass部分:

class MyClass { 
    String str; 
    Integer intgr; 
    /** 
    * Returns the relationship between this and another MyClass instance. 
    * The relationship can be one of three values: 
    * <pre> 
    * -1 - This object should be discarded and other kept 
    * 0 - There is no relationship between this and other 
    * 1 - This object should be kept and other discarded 
    * </pre> 
    * 
    * @param other The other instance to evaluate 
    * 
    * @return 0 if there is no relationship. 
    */ 
    public int relationTo(MyClass other) { 
     final String myPrefix = str.substring(0, str.length() - 1); 
     final String otherPrefix = other.str.substring(0, other.str.length() - 1); 
     if (myPrefix.equals(otherPrefix)) { 
      return intgr < other.intgr ? -1 : 1; 
     } else { 
      return 0; 
     } 
    } 
} 

(这可以很容易地转化为有两个参数的方法,这将是外界MyClass)。然后你可以使用的方法来决定如何继续。你需要做的双重迭代找到不相邻的对象:

int size = list.size(); 
for (int i = 0; i < size; ++i) { 
    final MyClass current = list.get(i); 
    for (int j = 0; j < i; ++j) { 
     final MyClass previous = list.get(j); 
     final int relation = previous.relationTo(current); 
     if (relation < 0) { 
      // remove previous (at index j) 
      list.remove(j); 
      --i; 
      --j; 
      --size; 
     } else if (relation > 0) { 
      // remove current (at index i) 
      list.remove(i); 
      --i; 
      --size; 
      break; // exit inner loop 
     } 
     // else current and previous don't share a prefix 
    } 
} 
+0

感谢您的回答!但想知道为什么我要从匹配的字符串中获得intgr中的samller值而不是我需要的大字符串! – divine

+0

@divine - 这是因为我根据'current'和'previous'之间的关系搞乱了最后一个代码块中的逻辑。我更新了我的答案(我希望)现在可以工作。 –

+0

谢谢!这就像一个魅力! – divine

1

你可以遍历您将它们添加到一个Map相关联的密钥(前缀)的值(对象)的元素集合。每次添加元素时,都要检查使用相同前缀存储的元素是否大于添加的元素。

为了有这样的行为:

provides this: [{a1 5}, {b2 3}, {g1 1}, {b5 1}, {c9 11}, {g2 3}, {d1 4}, {b3 19}] 
results this: [{a1 5}, {c9 11}, {g2 3}, {d1 4}, {b3 19}] 

您可以实现这样的事情:

import java.util.ArrayList; 
import java.util.LinkedHashMap; 
import java.util.List; 
import java.util.Map; 

public class TestSystemOut { 

    public static void main(final String[] a) { 
     List<MyObj> list = prepareList(); 
     System.out.println("provides this: " + list); 

     Map<String, MyObj> map = new LinkedHashMap<String, MyObj>(); // if result order doesn't matter this can be a simple HashMap 

     String strTmp; 
     for (MyObj obj : list) { 

      strTmp = obj.str; 
      strTmp = strTmp.substring(0, strTmp.length() - 1); 

      if (map.get(strTmp) == null || map.get(strTmp).integer < obj.integer) { 
       map.remove(strTmp); // this could be removed if order of result doesn't matter 
       map.put(strTmp, obj); 
      } 
     } 

     list.clear(); 
     list.addAll(map.values()); 

     System.out.println("results this: " + list); 
    } 

    public static class MyObj { 
     String str; 
     Integer integer; 

     public MyObj(final String str, final Integer integer) { 
      super(); 
      this.str = str; 
      this.integer = integer; 
     } 

     @Override 
     public String toString() { 
      return "{" + str + " " + integer + "}"; 
     } 

    } 

    private static List<MyObj> prepareList() { 
     List<MyObj> list = new ArrayList<MyObj>(); 
     list.add(new MyObj("a1", 5)); 
     list.add(new MyObj("b2", 3)); 
     list.add(new MyObj("g1", 1)); 
     list.add(new MyObj("b5", 1)); 
     list.add(new MyObj("c9", 11)); 
     list.add(new MyObj("g2", 3)); 
     list.add(new MyObj("d1", 4)); 
     list.add(new MyObj("b3", 19)); 
     return list; 
    } 
} 
+0

谢谢!这工作很好! :) – divine

0

另一个(可能更易于阅读&调试)的方法是:

  1. 将您的物品放入清单
  2. 遍历列表并填充一个Map,其中String是字母,MyClass是最小值(即,如果地图已经包含的东西“是”,请检查您的新MyClass的是更大或更小,相应的更换)

简单实现:

public class Test { 

    public static void main(String[] args) throws InterruptedException { 
     List<MyClass> list = Arrays.asList(new MyClass("a1", 5), 
       new MyClass("b2", 3), 
       new MyClass("g1", 1), 
       new MyClass("b5", 1), 
       new MyClass("c9", 11), 
       new MyClass("g2", 3), 
       new MyClass("d1", 4), 
       new MyClass("b3", 19)); 

     Map<String, MyClass> map = new HashMap<String, MyClass>(); 

     for (MyClass mc : list) { 
      MyClass current = map.get(mc.getLetter()); 
      if (current == null || mc.intgr > current.intgr) { 
       map.put(mc.getLetter(), mc); 
      } 
     } 
     System.out.println(map); 
    } 

    static class MyClass { 

     String str; 
     Integer intgr; 

     MyClass(String str, Integer intgr) { 
      this.str = str; 
      this.intgr = intgr; 
     } 
     String getLetter() { 
      return str.substring(0,1); 
     } 

     @Override 
     public String toString() { 
      return "[" + str + " " + intgr + "]"; 
     } 
    } 
} 
+0

感谢您的回答! – divine

0
/* 
* For every string in the list, look at all strings in the 
* list and compare the substring from 0 to length-1, if they 
* match and the id is not the same as the current s (i.e. s and 
* list.get(i) are at the same address) then remove that string. 
*/ 
public ArrayList remdup(ArrayList<String> list) { 

    for (String s : list) { 
     for (int i=0; i<list.size();i++) { 
      if (s.substring(0, s.length()-1).compareTo(list.get(i).substring(0, list.get(i).length()-1)) == 0 
        && list.indexOf(list.get(i)) != list.indexOf(s)) { 
       list.remove(list.get(i)); 
      } 
     } 
    } 
    return list; 
} 

也许试试这个,避风港尚未测试,但数字应该工作。如果它不尝试使用与compareTo()不同的东西,可以使用equals()作为替代。

此外,您将收到IndexOutOfBoundsException,因为每次删除元素时都会减去大小,从而缩小搜索范围。你没有考虑到remove()会为你做这件事。

我会考虑使用一个地图,而不是一个类。这样你就不必重新发明轮子。

+0

感谢您的回答! – divine

相关问题