删除重复项(两个值) - 从ArrayList重复值

时间:2015-10-14 13:17:10

标签: java arraylist

我有一个ArrayList,其中包含以下字符串;

 List<String> e = new ArrayList<String>();
 e.add("123");
 e.add("122");
 e.add("125");
 e.add("123");

我想检查列表中的重复项并将其从列表中删除。在这种情况下,我的列表将只有两个值,在这个例子中,它将是值122和125,并且两个123将消失。

最好的方法是什么?我正在考虑使用Set,但这只会删除其中一个重复项。

11 个答案:

答案 0 :(得分:24)

在Java 8中,你可以这样做:

e.removeIf(s -> Collections.frequency(e, s) > 1);

如果是!Java 8,您可以创建HashMap<String, Integer>。如果字符串已经出现在地图中,请将其增加1,否则,将其添加到地图中。

例如:

put("123", 1);

现在我们假设您再次拥有“123”,您应该获得密钥的计数并添加一个:

put("123", get("aaa") + 1);

现在,您可以轻松地在地图上进行迭代,并使用其值为&lt;的键创建一个新的数组列表。 2。

参考文献:

答案 1 :(得分:11)

您还可以在Java 8中使用filter

e.stream().filter(s -> Collections.frequency(e, s) == 1).collect(Collectors.toList())

答案 2 :(得分:6)

您可以使用HashMap<String, Integer>

您遍历列表,如果哈希映射不包含字符串,则将其与值1一起添加。

另一方面,如果您已经拥有该字符串,则只需递增计数器即可。因此,字符串的映射如下所示:

{"123", 2}
{"122", 1}
{"125", 1}

然后,您将创建一个新列表,其中每个键的值为1.

答案 3 :(得分:4)

这是一个使用map来计算出现次数的非Java 8解决方案:

Map map = new HashMap<String, Integer>()
for (String s : list){
    if (map.get(s)==null){
      map.put(s, 1);
    } 
    else {
      map.put(s, map.get(s)+1);
    }
}

List<String> newList = new ArrayList<String>();

// Remove from list if there are multiples of them.
for (Map.Entry<String, String> entry : map.entrySet())
{
  if(entry.getValue() > 1){
    newList.add(entry.getKey());
  }
}

list.removeAll(newList);

答案 4 :(得分:2)

ArrayList中的解决方案

public static void main(String args[]) throws Exception {
      List<String> e = new ArrayList<String>();
      List<String> duplicate = new ArrayList<String>();
      e.add("123");
      e.add("122");
      e.add("125");
      e.add("123");

      for(String str : e){
          if(e.indexOf(str) != e.lastIndexOf(str)){
              duplicate.add(str);
          }
      }

      for(String str : duplicate){
          e.remove(str);              
      }

      for(String str : e){
          System.out.println(str);
      }
  }

答案 5 :(得分:2)

List<String> e = new ArrayList<String>();
e.add("123");
e.add("122");
e.add("125");
e.add("123");
e.add("125");
e.add("124");
List<String> sortedList = new ArrayList<String>();
for (String current : e){
    if(!sortedList.contains(current)){
        sortedList.add(current);
    }
    else{
        sortedList.remove(current);
    }
}
e.clear();
e.addAll(sortedList);

答案 6 :(得分:2)

使用流的最简单的解决方案具有O(n^2)时间复杂度。如果您在拥有数百万条目的List上试用它们,那么您将等待非常长的时间。 O(n)解决方案是:

list = list.stream()
           .collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()))
           .entrySet()
           .stream()
           .filter(e -> e.getValue() == 1)
           .map(Map.Entry::getKey)
           .collect(Collectors.toList());

在这里,我使用LinkedHashMap维护订单。请注意,静态导入可以简化collect部分。

这太复杂了,我认为使用for循环是此问题的最佳选择。

Map<String, Integer> map = new LinkedHashMap<>();
for (String s : list)
    map.merge(s, 1, Integer::sum);
list = new ArrayList<>();
for (Map.Entry<String, Integer> e : map.entrySet())
    if (e.getValue() == 1)
        list.add(e.getKey());

答案 7 :(得分:1)

像这样(使用Set):

Set<Object> blackList = new Set<>()

public void add(Object object) {
    if (blackList.exists(object)) {
        return;
    }
    boolean notExists = set.add(object);
    if (!notExists) {
       set.remove(object)
       blackList.add(object);
    }
}

答案 8 :(得分:1)

如果你要去装,那么你可以用两套来实现它。在另一组中维护重复值,如下所示:

List<String> duplicateList = new ArrayList<String>();

duplicateList.add("123");
duplicateList.add("122");
duplicateList.add("125");
duplicateList.add("123");
duplicateList.add("127");
duplicateList.add("127");

System.out.println(duplicateList);

Set<String> nonDuplicateList = new TreeSet<String>();
Set<String> duplicateValues = new TreeSet<String>();

if(nonDuplicateList.size()<duplicateList.size()){
    for(String s: duplicateList){
        if(!nonDuplicateList.add(s)){
            duplicateValues.add(s);
        }
    }

    duplicateList.removeAll(duplicateValues);

    System.out.println(duplicateList);
    System.out.println(duplicateValues);
}
  

输出:原始列表:[123,122,125,123,127,127]。删除后   复制:[122,125]重复的值:[123,127]
  
  
  注意:此解决方案可能未进行优化。你可能会找到一个更好的   比这个解决方案。

答案 9 :(得分:1)

我是Google Guava API的粉丝。使用Collections2实用程序和通用的Predicate实现,可以创建一个实用方法来覆盖多种数据类型。

  

这假设有问题的对象具有有意义的.equals   实施

@Test
    public void testTrimDupList() {
        Collection<String> dups = Lists.newArrayList("123", "122", "125", "123");
        dups = removeAll("123", dups);
        Assert.assertFalse(dups.contains("123"));

        Collection<Integer> dups2 = Lists.newArrayList(123, 122, 125,123);
        dups2 = removeAll(123, dups2);
        Assert.assertFalse(dups2.contains(123));
    }

    private <T> Collection<T> removeAll(final T element, Collection<T> collection) {
        return Collections2.filter(collection, new Predicate<T>(){
            @Override
            public boolean apply(T arg0) {
                return !element.equals(arg0);
            }});
    }

更多地考虑这个

本页中的大多数其他示例都使用java.util.List API作为基本Collection。我不确定是否使用intent完成,但如果返回的元素必须是List,则可以使用另一个中间方法,如下所示。多态性ftw!

@Test
    public void testTrimDupListAsCollection() {
        Collection<String> dups = Lists.newArrayList("123", "122", "125", "123");
        //List used here only to get access to the .contains method for validating behavior.
        dups = Lists.newArrayList(removeAll("123", dups)); 
        Assert.assertFalse(dups.contains("123"));

        Collection<Integer> dups2 = Lists.newArrayList(123, 122, 125,123);
      //List used here only to get access to the .contains method for validating behavior.
        dups2 = Lists.newArrayList(removeAll(123, dups2));
        Assert.assertFalse(dups2.contains(123));
    }

    @Test
    public void testTrimDupListAsList() {
        List<String> dups = Lists.newArrayList("123", "122", "125", "123");
        dups = removeAll("123", dups);
        Assert.assertFalse(dups.contains("123"));

        List<Integer> dups2 = Lists.newArrayList(123, 122, 125,123);
        dups2 = removeAll(123, dups2);
        Assert.assertFalse(dups2.contains(123));
    }

    private <T> List<T> removeAll(final T element, List<T> collection) {
        return Lists.newArrayList(removeAll(element, (Collection<T>) collection));

    }
    private <T> Collection<T> removeAll(final T element, Collection<T> collection) {
        return Collections2.filter(collection, new Predicate<T>(){
            @Override
            public boolean apply(T arg0) {
                return !element.equals(arg0);
            }});
    }

答案 10 :(得分:0)

使用Guava库,使用多集和流:

e = HashMultiset.create(e).entrySet().stream()
    .filter(me -> me.getCount() > 1)
    .map(me -> me.getElement())
    .collect(toList());

对于大型列表( O(n)具有相当大的常数因子),这是相当快且相当快的。但它不保留顺序(如果需要可以使用LinkedHashMultiset)并且它会创建一个新的列表实例。

也很容易概括,例如,删除所有三次重复。

通常,多集数据结构对于保留在工具箱中非常有用。