ArrayList에서 반복되는 요소를 어떻게 제거합니까?


답변:


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 2016.

4
좋은 연습은 인터페이스 유형을 사용하여 변수를 정의하는 것 ListSet(대신 구현 유형 ArrayListHashSet같은 예에서).
Jonik

33
new HashSet(al)이를 비우고 호출 하는 대신 초기화 하여 사용하여 정리할 수 있습니다 addAll.
ashes999

1
중복 항목을 설정하는 규칙을 추가 할 수 있습니까? 예를 들어 Object, 두 값이 반복 되면 내 값이 여러 개인 경우 값을 중복으로 간주하고 (다른 값은 다를 수 있음) Set?
Jean d' arme

290

변환하더라도 ArrayListA를가 HashSet효과적으로 중복 제거 당신이 삽입 순서를 유지해야하는 경우, 차라리이 변형을 사용하는 것이 좋을 것

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

그런 다음 List참조를 다시 가져와야하는 경우 변환 생성자를 다시 사용할 수 있습니다.


10
LinkedHashSet은 목록에서 몇 개의 복제본 중 어느 것이 유지되는지 보증합니까? 예를 들어, 1, 3 및 5 위치가 원래 목록에서 중복 된 경우이 프로세스가 3 및 5를 제거한다고 가정 할 수 있습니까? 아니면 1과 3을 제거 하시겠습니까? 감사.
Matt Briançon

16
@ 매트 : 예, 보장합니다. 문서를 말한다 : "이 링크리스트 요소가 설정 (삽입 순서)에 삽입 된 순서가 반복 순서를 정의하는 요소가 재 삽입 된 세트로하는 경우, 삽입 순서는 영향을받지 않는다 참고.."
abahgat

매우 흥미로운. 나는 여기에 다른 상황이 있습니다. String을 정렬하려고하지 않지만 AwardYearSource라는 다른 객체를 정렬하려고합니다. 이 클래스에는 year라는 int 속성이 있습니다. 연도를 기준으로 중복을 제거하고 싶습니다. 즉, 2010 년이 두 번 이상 언급 된 경우 해당 AwardYearSource 개체를 제거하고 싶습니다. 어떻게해야합니까?
WowBow

@WowBow 예를 들어 AwardYearSource를 보유하는 Wrapper 객체를 정의 할 수 있습니다. 그리고 AwardYearSources 연도 필드를 기반으로이 래퍼 객체와 동일한 방법을 정의하십시오. 그런 다음이 래퍼 객체와 함께 Set을 사용할 수 있습니다.
Ondrej Bozek 2016 년

@WowBow 또는 Comparable / Comparator 구현
shrini1000

134

자바 8 :

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

있습니다 해시 코드가-동일 리스트 회원을위한 계약은 제대로 작동하려면 필터링 존중해야한다.


1
대소 문자를 구분하지 않는 구별하려면 어떻게해야합니까?
StackFlowed

당신은 당신이 할 수있는 목록의 순서 보존 할 필요가없는 경우 @StackFlowed addAll하는 방법을 new TreeSet<String>(String.CASE_INSENSITIVE_ORDER). 추가 된 첫 번째 요소는 목록에 "Dog"및 "dog"(순서대로) TreeSet이 포함 된 경우 "Dog"을 포함 하는 세트로 유지 됩니다. 순서를 유지해야하는 경우에는 답의 행 앞에을 두십시오 list.replaceAll(String::toUpperCase);.
Paul

1
이 오류가 발생합니다 : 호환되지 않는 유형 : List <Object>를 List <String>으로 변환 할 수 없습니다
Samir

이것은 일반적으로 간단한 해결책이지만 int []의 Arraylist에서 중복을 어떻게 제거합니까?
Nooby Programmer

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());이 경우에 적합한 솔루션이어야합니다
Diablo

53

중복을 원하지 않으면 a 대신 Set을 사용 하십시오List . 를 a List로 변환하려면 Set다음 코드를 사용할 수 있습니다.

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

당신은 변환 동일한 구성을 사용할 수 있습니다 정말 필요한 경우 Set에 다시 List.


마찬가지로 스레드의 맨 아래에서 Set for Custom Object를 사용하는 위치에 대한 답변을 제공했습니다. "Contact"또는 "Student"와 같은 사용자 지정 개체가있는 사람은 저에게 잘 맞는 대답을 사용할 수 있습니다.
Muhammad Adil

요소에 특별히 액세스해야 할 때 문제가 발생합니다. 예를 들어 Android에서 객체를 목록 항목보기에 바인딩 할 때 색인이 제공됩니다. 따라서 Set여기서 사용할 수 없습니다.
TheRealChx101

리스트가 객체리스트 일 때 어떻게 이것을 접근시킬 수 있습니까?
jvargas

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());

arraylist에서 중복 요소를 제거하는 방법


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는 반복되는 항목이없는 목록입니다 (YouClass에 평등을 유지하려는 항목에 따라 equals 메소드가 있는지 확인하십시오)


이 대답에는 두 가지가 부족합니다. 1) 제네릭을 사용하지 않지만 원시 유형 ( ArrayList<T>대신에 사용해야 함 ArrayList) 2)을 사용하여 명시 적 반복자 생성을 피할 수 있습니다 for (T current : l1) { ... }. Iterator명시 적으로 사용하고 싶더라도 iterador철자가 잘못되었습니다.
RAnders00

4
이 구현은 선형 시간으로 실행되는 연결된 해시 세트 구현과 비교하여 2 차 시간으로 실행됩니다. (즉, 10 개의 요소가있는 목록에서는 10 배, 10,000 개의 요소가있는 목록에서는 10,000 배 더 오래 걸립니다. ArrayList .를위한 JDK 6 구현은 JDK8 impl이 동일합니다.)
Patrick M

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 그 코드를 사용해 보셨습니까?. 예외는 발생하지 않으며 매우 빠릅니다. 게시하기 전에 코드를 사용해 보았습니다.
CarlJohn

4
맞습니다. 목록 대신 배열을 반복하지는 않습니다. 그러나 그것은 지옥처럼 느립니다. 수백만 요소로 사용해보십시오. 와 비교하십시오 ImmutableSet.copyOf(lst).toList().
maaartinus

인터뷰에서 요청한 질문에 대답합니다. Sets를 사용하지 않고 ArrayList에서 반복되는 값을 제거하는 방법. 고맙습니다
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

12

아마 약간 과잉이지만, 나는 이런 종류의 고립 된 문제를 즐깁니다. :)

이 코드는 고유성 검사를 위해 임시 세트를 사용하지만 원래 목록 내에서 직접 요소를 제거합니다. ArrayList 내에서 요소를 제거하면 많은 양의 배열 복사가 발생할 수 있으므로 remove (int) -method가 방지됩니다.

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
    }
}

편집 : generics-stuff는 실제로 여기에 어떤 가치도 추가하지 않는다고 생각합니다. 오. :)


1
매개 변수에 ArrayList를 사용하는 이유는 무엇입니까? 왜 목록을 작성하지 않습니까? 작동하지 않습니까?
Shervin Asgari

목록은 나열된 첫 번째 방법의 매개 변수로 절대 작동 합니다. 그러나이 방법은 ArrayList와 같은 임의 액세스 목록과 함께 사용 하도록 최적화 되었으므로 LinkedList가 전달되면 성능이 저하됩니다. 예를 들어, LinkedList에서 n : th 요소를 설정하는 데 O (n) 시간이 걸리는 반면 임의 액세스 목록 (예 : ArrayList)에서 n : th 요소를 설정하려면 O (1) 시간이 걸립니다. 다시 말하지만, 이것은 아마도 과잉 일 것입니다 ... 이런 종류의 특수 코드가 필요하면 격리 된 상황에 있기를 바랍니다.
발리

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 때문에 목록에 요소를 반환하지 않습니다.
neo7

1
이 구현 작업은 매우 훌륭합니다.이 문제에는 아무런 문제가 없으며이 작업에는 하나의 arraylist 만 사용 하므로이 답변은 완전히 좋습니다. 부정적인 피드백을주기 전에 테스트 케이스를 추가하여 모든 사람이 결과를 이해할 수 있도록하십시오. 감사합니다. 감사합니다. Manash
Manash Ranjan Dakua

5

써드 파티 라이브러리를 사용하려는 경우 Eclipse Collections (이전 GS Collections) 의 메소드 distinct()를 사용할 수 있습니다 .

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

distinct()집합으로 변환 한 다음 다시 목록으로 변환 하는 대신 사용 하는 이점은 distinct()원래 목록의 순서를 유지하고 각 요소의 첫 항목을 유지한다는 것입니다. 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, 10}을 얻게됩니다


2

주문을 유지하려면 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

앞에서 언급했듯이 요소 대신 유니티를 확보하려면 List 대신 Set 인터페이스를 구현하는 클래스를 사용해야합니다. 요소 순서를 유지해야하는 경우 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
이미 2 년 된 선형 및 로그 선형 솔루션이있는 질문에 이차 솔루션을 게시하는 이유는 무엇입니까?
abarnert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.