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

我有一个带有以下字符串的ArrayList ;

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

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

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

在Java 8中,您可以:

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

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

例如:

 put("123", 1); 

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

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

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

参考文献:

  • ArrayList#removeIf
  • Collections#frequency
  • HashMap

您还可以在Java 8中使用filter

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

您可以使用HashMap

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

另一方面,如果你已经有了字符串,你只需增加计数器。 因此,您的字符串的映射将如下所示:

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

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

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

 Map map = new HashMap() for (String s : list){ if (map.get(s)==null){ map.put(s, 1); } else { map.put(s, map.get(s)+1); } } List newList = new ArrayList(); // Remove from list if there are multiples of them. for (Map.Entry entry : map.entrySet()) { if(entry.getValue() > 1){ newList.add(entry.getKey()); } } list.removeAll(newList); 

ArrayList中的解决方案

 public static void main(String args[]) throws Exception { List e = new ArrayList(); List duplicate = new ArrayList(); 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); } } 

使用流的最简单的解决方案具有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 map = new LinkedHashMap<>(); for (String s : list) map.merge(s, 1, Integer::sum); list = new ArrayList<>(); for (Map.Entry e : map.entrySet()) if (e.getValue() == 1) list.add(e.getKey()); 
 List e = new ArrayList(); e.add("123"); e.add("122"); e.add("125"); e.add("123"); e.add("125"); e.add("124"); List sortedList = new ArrayList(); for (String current : e){ if(!sortedList.contains(current)){ sortedList.add(current); } else{ sortedList.remove(current); } } e.clear(); e.addAll(sortedList); 

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

这假定所讨论的对象具有有意义的.equals实现

 @Test public void testTrimDupList() { Collection dups = Lists.newArrayList("123", "122", "125", "123"); dups = removeAll("123", dups); Assert.assertFalse(dups.contains("123")); Collection dups2 = Lists.newArrayList(123, 122, 125,123); dups2 = removeAll(123, dups2); Assert.assertFalse(dups2.contains(123)); } private  Collection removeAll(final T element, Collection collection) { return Collections2.filter(collection, new Predicate(){ @Override public boolean apply(T arg0) { return !element.equals(arg0); }}); } 

再考虑一下这个

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

 @Test public void testTrimDupListAsCollection() { Collection 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 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 dups = Lists.newArrayList("123", "122", "125", "123"); dups = removeAll("123", dups); Assert.assertFalse(dups.contains("123")); List dups2 = Lists.newArrayList(123, 122, 125,123); dups2 = removeAll(123, dups2); Assert.assertFalse(dups2.contains(123)); } private  List removeAll(final T element, List collection) { return Lists.newArrayList(removeAll(element, (Collection) collection)); } private  Collection removeAll(final T element, Collection collection) { return Collections2.filter(collection, new Predicate(){ @Override public boolean apply(T arg0) { return !element.equals(arg0); }}); } 

像这样的东西(使用Set ):

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

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

 List duplicateList = new ArrayList(); duplicateList.add("123"); duplicateList.add("122"); duplicateList.add("125"); duplicateList.add("123"); duplicateList.add("127"); duplicateList.add("127"); System.out.println(duplicateList); Set nonDuplicateList = new TreeSet(); Set duplicateValues = new TreeSet(); if(nonDuplicateList.size() 

输出:原始列表:[123,122,125,123,127,127]。 删除后
副本:[122,125]重复的值:[123,127]

注意:此解决方案可能未进行优化。 你可能会发现更好的
解决方案比这个。

使用Guava库,使用multiset和streams:

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

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

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

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