如何从ArrayList中删除重复的元素?


Answers:


991

如果您不想在中使用重复项Collection,则应考虑为什么使用Collection允许重复项的。删除重复元素的最简单方法是将内容添加到中Set(不允许重复),然后将其添加Set回中ArrayList

Set<String> set = new HashSet<>(yourList);
yourList.clear();
yourList.addAll(set);

当然,这会破坏中的元素顺序ArrayList


260
如果您希望保留订单,请参见LinkedHashSet。
凌空

3
@Chetan从O(n)的ArrayList中查找所有重复项,对在列表中具有的对象正确定义equals方法很重要(数字没有问题): public Set<Object> findDuplicates(List<Object> list) { Set<Object> items = new HashSet<Object>(); Set<Object> duplicates = new HashSet<Object>(); for (Object item : list) { if (items.contains(item)) { duplicates.add(item); } else { items.add(item); } } return duplicates; }
Ondrej Bozek 2012年

4
一个好的做法是使用ListSet(而不是实现类型ArrayListHashSet您的示例中的)接口类型来定义变量。
约尼克,

33
您可以通过使用new HashSet(al)而不是将其初始化为空并调用来清理它addAll
ashes999 2013年

1
我可以添加规则来设置重复项吗?例如:当我Object有多个值(如果其中两个重复)时,我会将其视为重复值(其他值可以不同)并使用Set
Jean d'arme

290

尽管将转换ArrayListHashSet有效删除了重复项,但如果您需要保留插入顺序,我还是建议您使用此变体

// list is some List of Strings
Set<String> s = new LinkedHashSet<>(list);

然后,如果需要获取List参考,则可以再次使用转换构造函数。


10
LinkedHashSet是否保证从列表中保留几个重复项中的哪个?例如,如果位置1、3和5在原始列表中是重复的,我们是否可以假定此过程将删除3和5?或者删除1和3?谢谢。
马特·布莱恩松(MattBriançon),

16
@Matt:是的,它确实保证了这一点。的文档说:“这链接列表定义迭代排序,这是在其中元件被插入到该组(插入顺序)的顺序请注意,如果一个元素是重新插入到组插入顺序不受影响。”。
2011年

很有意思。我在这里有不同的情况。我不是在尝试对String进行排序,而是对另一个称为AwardYearSource的对象进行排序。此类具有一个名为year的int属性。所以我想根据年份删除重复项。即如果提到的2010年不止一次,我想删除那个AwardYearSource对象。我怎样才能做到这一点?
WowBow 2012年

@WowBow例如,您可以定义保存有AwardYearSource的Wrapper对象。并基于AwardYearSources年字段定义此Wrapper对象equals方法。然后,可以将Set与这些Wrapper对象一起使用。
Ondrej Bozek 2012年

@WowBow或实现Comparable / Comparator
shrini1000

134

在Java 8中:

List<String> deduped = list.stream().distinct().collect(Collectors.toList());

请注意,应遵循列表成员的hashCode-equals合同,以使过滤正常工作。


1
对于不区分大小写的区别,我该怎么做?
StackFlowed

@StackFlowed如果您不需要保留的列表,你可以的顺序做addAllnew TreeSet<String>(String.CASE_INSENSITIVE_ORDER)。添加的第一个元素将保留在集合中,因此,如果您的列表包含“ Dog”和“ dog”(按此顺序),TreeSet则将包含“ Dog”。如果必须保留顺序,则在答案行之前放list.replaceAll(String::toUpperCase);
保罗

1
我收到此错误:不兼容的类型:无法将List <Object>转换为List <String>
Samir '18

通常,这是一个简单的解决方案,但是如何从int []的Arraylist中删除重复项?
Nooby程序员

56

假设我们有一个String类似的清单:

List<String> strList = new ArrayList<>(5);
// insert up to five items to list.        

然后,我们可以通过多种方式删除重复的元素。

Java 8之前的版本

List<String> deDupStringList = new ArrayList<>(new HashSet<>(strList));

注意:如果我们要保持插入顺序,则需要使用LinkedHashSet代替HashSet

使用番石榴

List<String> deDupStringList2 = Lists.newArrayList(Sets.newHashSet(strList));

使用Java 8

List<String> deDupStringList3 = strList.stream().distinct().collect(Collectors.toList());

注意: 如果要在特定的列表实现中收集结果,例如LinkedList,可以将上面的示例修改为:

List<String> deDupStringList3 = strList.stream().distinct()
                 .collect(Collectors.toCollection(LinkedList::new));

我们也parallelStream可以在上面的代码中使用它,但是它可能无法带来预期的性能优势。查看更多此问题


是的,当我键入以前的评论时,我的印象是parallel streams始终可以提供更好的性能。但这是一个神话。后来我了解到,在某些情况下应使用并行流。在这种情况下,并行流不会提供任何更好的性能。是的,在某些情况下,并行流可能无法提供预期的结果。List<String> deDupStringList3 = stringList.stream().map(String::toLowerCase).distinct().collect(Collectors.toList());在这种情况下应该是合适的解决方案
暗黑破坏神

53

如果您不想重复,请使用Set而不是List。要将a转换List为a Set,可以使用以下代码:

// list is some List of Strings
Set<String> s = new HashSet<String>(list);

如果确实需要,您可以使用相同的构造将a转换Set回a List


同样,在线程底部,我给出了一个答案,我正在使用Set for Custom Object。如果有人拥有“联系人”或“学生”之类的自定义对象,则可以使用对我来说很好的答案。
穆罕默德·阿迪尔

当您必须专门访问元素时,就会出现问题。例如,在Android中将对象绑定到列表项视图时,将为其指定索引。所以Set不能在这里使用。
TheRealChx101 '19

当列表是对象列表时,我该如何
辩解

28

您也可以通过这种方式来保存订单:

// delete duplicates (if any) from 'myArrayList'
myArrayList = new ArrayList<String>(new LinkedHashSet<String>(myArrayList));

我认为这是删除ArrayList中重复项的最好方法。绝对推荐。谢谢@Nenad的回答。
ByWaleed

25

Java 8流提供了一种非常简单的方法来从列表中删除重复的元素。使用独特的方法。如果我们有一个城市列表,并且想要从该列表中删除重复项,则可以在一行中完成-

 List<String> cityList = new ArrayList<>();
 cityList.add("Delhi");
 cityList.add("Mumbai");
 cityList.add("Bangalore");
 cityList.add("Chennai");
 cityList.add("Kolkata");
 cityList.add("Mumbai");

 cityList = cityList.stream().distinct().collect(Collectors.toList());

如何从数组列表中删除重复的元素


25

这是一种不影响您的列表顺序的方法:

ArrayList l1 = new ArrayList();
ArrayList l2 = new ArrayList();

Iterator iterator = l1.iterator();

while (iterator.hasNext()) {
    YourClass o = (YourClass) iterator.next();
    if(!l2.contains(o)) l2.add(o);
}

l1是原始列表,l2是没有重复项的列表(请确保YourClass根据要代表的相等性使用equals方法)


这个答案缺少两点:1)它不使用泛型,而是原始类型(ArrayList<T>应使用原始类型ArrayList)2)通过使用,可以避免显式迭代器的创建for (T current : l1) { ... }。即使您想Iterator显式使用,iterador也是拼写错误。
RAnders00 2015年

4
与以线性时间运行的链接哈希集实现相比,该实现以二次时间运行。(即这需要10倍的时间有10个元素,10,000倍不再与10,000个元素的列表上的列表上JDK 6实施。ArrayList.contains,JDK8 IMPL是相同的。)
帕特里克中号

21

无需使用HashSet一个以上的arraylist,就可以从arraylist中删除重复项。

试试这个代码。

    ArrayList<String> lst = new ArrayList<String>();
    lst.add("ABC");
    lst.add("ABC");
    lst.add("ABCD");
    lst.add("ABCD");
    lst.add("ABCE");

    System.out.println("Duplicates List "+lst);

    Object[] st = lst.toArray();
      for (Object s : st) {
        if (lst.indexOf(s) != lst.lastIndexOf(s)) {
            lst.remove(lst.lastIndexOf(s));
         }
      }

    System.out.println("Distinct List "+lst);

输出为

Duplicates List [ABC, ABC, ABCD, ABCD, ABCE]
Distinct List [ABC, ABCD, ABCE]

它很慢,您可能会收到ConcurrentModificationException。
maaartinus

@maaartinus您是否尝试过该代码?它不会产生任何异常,而且速度非常快。我在发布之前尝试了代码。
约翰·卡尔(John CarlJohn),

4
没错,当您迭代数组而不是列表时,它不是。但是,它慢得要命。尝试使用几百万个元素。比较一下ImmutableSet.copyOf(lst).toList()
maaartinus

回答我在面试中被问到的问题..如何在不使用Set的情况下从ArrayList中删除重复值。Thanx
Aniket Paul

在内部,使用for循环进行indexOf迭代lst
Patrick M


19

这样可以解决问题:

private List<SomeClass> clearListFromDuplicateFirstName(List<SomeClass> list1) {

     Map<String, SomeClass> cleanMap = new LinkedHashMap<String, SomeClass>();
     for (int i = 0; i < list1.size(); i++) {
         cleanMap.put(list1.get(i).getFirstName(), list1.get(i));
     }
     List<SomeClass> list = new ArrayList<SomeClass>(cleanMap.values());
     return list;
}

1
我更喜欢这种解决方案。
Tushar Gogna's

12

可能有点矫kill过正,但我​​喜欢这种孤立的问题。:)

此代码使用一个临时Set(用于唯一性检查),但是直接删除原始列表中的元素。由于ArrayList内部元素的删除会导致大量的数组复制,因此避免了remove(int)方法。

public static <T> void removeDuplicates(ArrayList<T> list) {
    int size = list.size();
    int out = 0;
    {
        final Set<T> encountered = new HashSet<T>();
        for (int in = 0; in < size; in++) {
            final T t = list.get(in);
            final boolean first = encountered.add(t);
            if (first) {
                list.set(out++, t);
            }
        }
    }
    while (out < size) {
        list.remove(--size);
    }
}

当我们使用它时,这是LinkedList的一个版本(好多了!):

public static <T> void removeDuplicates(LinkedList<T> list) {
    final Set<T> encountered = new HashSet<T>();
    for (Iterator<T> iter = list.iterator(); iter.hasNext(); ) {
        final T t = iter.next();
        final boolean first = encountered.add(t);
        if (!first) {
            iter.remove();
        }
    }
}

使用标记界面为List呈现统一的解决方案:

public static <T> void removeDuplicates(List<T> list) {
    if (list instanceof RandomAccess) {
        // use first version here
    } else {
        // use other version here
    }
}

编辑:我想泛型的东西并没有真正在这里添加任何值..哦,很好。:)


1
为什么在参数中使用ArrayList?为什么不只是列出?那行不通吗?
Shervin Asgari

对于列出的第一种方法,列表绝对可以作为参数使用。但是,该方法已针对与ArrayList之类的随机访问列表一起使用进行了优化,因此,如果传递了LinkedList,则性能会很差。例如,在LinkedList中设置第n个元素花费O(n)时间,而在随机访问列表(例如ArrayList)中设置第n个元素花费O(1)时间。再次,但是,这可能是矫kill过正……如果您需要这种特殊的代码,则希望它处于孤立的情况。
凌空抽射

10
public static void main(String[] args){
    ArrayList<Object> al = new ArrayList<Object>();
    al.add("abc");
    al.add('a');
    al.add('b');
    al.add('a');
    al.add("abc");
    al.add(10.3);
    al.add('c');
    al.add(10);
    al.add("abc");
    al.add(10);
    System.out.println("Before Duplicate Remove:"+al);
    for(int i=0;i<al.size();i++){
        for(int j=i+1;j<al.size();j++){
            if(al.get(i).equals(al.get(j))){
                al.remove(j);
                j--;
            }
        }
    }
    System.out.println("After Removing duplicate:"+al);
}

由于最后一个
j--,

1
这个实现工作非常好。没有问题,为此任务我只使用一个arraylist.so这个答案是完全好的。在给出负面反馈之前,您还要添加测试用例,以便每个人都可以理解结果。 Manash
Manash Ranjan Dakua 2015年

5

如果你愿意使用第三方库,你可以使用的方法distinct()Eclipse中集(原GS集合)。

ListIterable<Integer> integers = FastList.newListWith(1, 3, 1, 2, 2, 1);
Assert.assertEquals(
    FastList.newListWith(1, 3, 2),
    integers.distinct());

使用distinct()而不是转换为Set然后再转换为List 的优点是distinct()保留了原始List的顺序,并保留了每个元素的第一次出现。通过同时使用Set和List来实现。

MutableSet<T> seenSoFar = UnifiedSet.newSet();
int size = list.size();
for (int i = 0; i < size; i++)
{
    T item = list.get(i);
    if (seenSoFar.add(item))
    {
        targetCollection.add(item);
    }
}
return targetCollection;

如果无法将原始List转换为Eclipse Collections类型,则可以使用ListAdapter获得相同的API。

MutableList<Integer> distinct = ListAdapter.adapt(integers).distinct();

注意:我是Eclipse Collections的提交者。


3

这三行代码可以从ArrayList或任何集合中删除重复的元素。

List<Entity> entities = repository.findByUserId(userId);

Set<Entity> s = new LinkedHashSet<Entity>(entities);
entities.clear();
entities.addAll(s);

2

填充ArrayList时,请为每个元素使用一个条件。例如:

    ArrayList< Integer > al = new ArrayList< Integer >(); 

    // fill 1 
    for ( int i = 0; i <= 5; i++ ) 
        if ( !al.contains( i ) ) 
            al.add( i ); 

    // fill 2 
    for (int i = 0; i <= 10; i++ ) 
        if ( !al.contains( i ) ) 
            al.add( i ); 

    for( Integer i: al )
    {
        System.out.print( i + " ");     
    }

我们将得到一个数组{0,1,2,3,4,5,6,7,8,9,9,10}


2

如果要保留您的Order,那么最好使用LinkedHashSet。因为如果您希望通过迭代将该列表传递给插入查询,则将保留顺序。

尝试这个

LinkedHashSet link=new LinkedHashSet();
List listOfValues=new ArrayList();
listOfValues.add(link);

当您要返回列表而不是集合时,此转换将非常有帮助。


2

码:

List<String> duplicatList = new ArrayList<String>();
duplicatList = Arrays.asList("AA","BB","CC","DD","DD","EE","AA","FF");
//above AA and DD are duplicate
Set<String> uniqueList = new HashSet<String>(duplicatList);
duplicatList = new ArrayList<String>(uniqueList); //let GC will doing free memory
System.out.println("Removed Duplicate : "+duplicatList);

注意:肯定会有内存开销。


2
ArrayList<String> city=new ArrayList<String>();
city.add("rajkot");
city.add("gondal");
city.add("rajkot");
city.add("gova");
city.add("baroda");
city.add("morbi");
city.add("gova");

HashSet<String> hashSet = new HashSet<String>();
hashSet.addAll(city);
city.clear();
city.addAll(hashSet);
Toast.makeText(getActivity(),"" + city.toString(),Toast.LENGTH_SHORT).show();

1

LinkedHashSet可以解决问题。

String[] arr2 = {"5","1","2","3","3","4","1","2"};
Set<String> set = new LinkedHashSet<String>(Arrays.asList(arr2));
for(String s1 : set)
    System.out.println(s1);

System.out.println( "------------------------" );
String[] arr3 = set.toArray(new String[0]);
for(int i = 0; i < arr3.length; i++)
     System.out.println(arr3[i].toString());

//输出:5、1、2、3、4


1
        List<String> result = new ArrayList<String>();
        Set<String> set = new LinkedHashSet<String>();
        String s = "ravi is a good!boy. But ravi is very nasty fellow.";
        StringTokenizer st = new StringTokenizer(s, " ,. ,!");
        while (st.hasMoreTokens()) {
            result.add(st.nextToken());
        }
         System.out.println(result);
         set.addAll(result);
        result.clear();
        result.addAll(set);
        System.out.println(result);

output:
[ravi, is, a, good, boy, But, ravi, is, very, nasty, fellow]
[ravi, is, a, good, boy, But, very, nasty, fellow]

1

这用于您的“自定义对象”列表

   public List<Contact> removeDuplicates(List<Contact> list) {
    // Set set1 = new LinkedHashSet(list);
    Set set = new TreeSet(new Comparator() {

        @Override
        public int compare(Object o1, Object o2) {
            if (((Contact) o1).getId().equalsIgnoreCase(((Contact) o2).getId()) /*&&
                    ((Contact)o1).getName().equalsIgnoreCase(((Contact)o2).getName())*/) {
                return 0;
            }
            return 1;
        }
    });
    set.addAll(list);

    final List newList = new ArrayList(set);
    return newList;
}

1

您可以在下面使用嵌套循环:

ArrayList<Class1> l1 = new ArrayList<Class1>();
ArrayList<Class1> l2 = new ArrayList<Class1>();

        Iterator iterator1 = l1.iterator();
        boolean repeated = false;

        while (iterator1.hasNext())
        {
            Class1 c1 = (Class1) iterator1.next();
            for (Class1 _c: l2) {
                if(_c.getId() == c1.getId())
                    repeated = true;
            }
            if(!repeated)
                l2.add(c1);
        }

1

如前所述,您应该使用实现Set接口的类而不是List来确保元素的唯一性。如果必须保持元素的顺序,则可以使用SortedSet接口。TreeSet类实现该接口。


1

如果使用模型类型List <T> / ArrayList <T>。希望对您有帮助。

这是我的代码,未使用任何其他数据结构(例如set或hashmap)

for (int i = 0; i < Models.size(); i++){
for (int j = i + 1; j < Models.size(); j++) {       
 if (Models.get(i).getName().equals(Models.get(j).getName())) {    
 Models.remove(j);
   j--;
  }
 }
}

0
for(int a=0;a<myArray.size();a++){
        for(int b=a+1;b<myArray.size();b++){
            if(myArray.get(a).equalsIgnoreCase(myArray.get(b))){
                myArray.remove(b); 
                dups++;
                b--;
            }
        }
}

0
import java.util.*;
class RemoveDupFrmString
{
    public static void main(String[] args)
    {

        String s="appsc";

        Set<Character> unique = new LinkedHashSet<Character> ();

        for(char c : s.toCharArray()) {

            System.out.println(unique.add(c));
        }
        for(char dis:unique){
            System.out.println(dis);
        }


    }
}

0
public Set<Object> findDuplicates(List<Object> list) {
        Set<Object> items = new HashSet<Object>();
        Set<Object> duplicates = new HashSet<Object>();
        for (Object item : list) {
            if (items.contains(item)) {
                duplicates.add(item);
                } else { 
                    items.add(item);
                    } 
            } 
        return duplicates;
        }

0
    ArrayList<String> list = new ArrayList<String>();
    HashSet<String> unique = new LinkedHashSet<String>();
    HashSet<String> dup = new LinkedHashSet<String>();
    boolean b = false;
    list.add("Hello");
    list.add("Hello");
    list.add("how");
    list.add("are");
    list.add("u");
    list.add("u");

    for(Iterator iterator= list.iterator();iterator.hasNext();)
    {
        String value = (String)iterator.next();
        System.out.println(value);

        if(b==unique.add(value))
            dup.add(value);
        else
            unique.add(value);


    }
    System.out.println(unique);
    System.out.println(dup);

0

如果您想从ArrayList中删除重复项,则请找到以下逻辑,

public static Object[] removeDuplicate(Object[] inputArray)
{
    long startTime = System.nanoTime();
    int totalSize = inputArray.length;
    Object[] resultArray = new Object[totalSize];
    int newSize = 0;
    for(int i=0; i<totalSize; i++)
    {
        Object value = inputArray[i];
        if(value == null)
        {
            continue;
        }

        for(int j=i+1; j<totalSize; j++)
        {
            if(value.equals(inputArray[j]))
            {
                inputArray[j] = null;
            }
        }
        resultArray[newSize++] = value;
    }

    long endTime = System.nanoTime()-startTime;
    System.out.println("Total Time-B:"+endTime);
    return resultArray;
}

1
您为什么要针对已经存在两年的线性和对数线性解决方案(也更简单)的问题发布二次解?
abarnert 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.