development

목록에서 중복을 제거하는 방법은 무엇입니까?

big-blog 2020. 12. 31. 23:23
반응형

목록에서 중복을 제거하는 방법은 무엇입니까?


목록에서 중복 항목을 제거하고 싶지만 수행중인 작업이 작동하지 않습니다.

List<Customer> listCustomer = new ArrayList<Customer>();    
for (Customer customer: tmpListCustomer)
{
  if (!listCustomer.contains(customer)) 
  {
    listCustomer.add(customer);
  }
 }

그 코드가 작동하지 않는 경우, 당신은 아마 구현하지 않은 equals(Object)Customer적절 클래스입니다.

아마도 customerId고객을 고유하게 식별하는 키 (라고 부르겠습니다)가있을 것입니다 . 예 :

class Customer {
    private String customerId;
    ...

의 적절한 정의 equals(Object)는 다음과 같습니다.

    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof Customer)) {
            return false;
        }
        Customer other = (Customer) obj;
        return this.customerId.equals(other.customerId);
    }

완전성을 위해 동일한 개체가 동일한 해시 값을 반환 하도록 구현 해야 합니다. 위의 정의에 대한 일치 는 다음과 같습니다.hashCodeCustomerhashCodeequals

    public int hashCode() {
        return customerId.hashCode();
    }

목록이 큰 경우 중복을 제거하는 효율적인 방법이 아니라는 점도 주목할 가치가 있습니다. (N 명의 고객이있는 목록 N*(N-1)/2의 경우 최악의 경우 (예 : 중복이없는 경우) 비교 를 수행해야합니다 .)보다 효율적인 솔루션을 위해 a와 같은 것을 사용 HashSet하여 중복 검사를 수행해야합니다.


현재 순서를 유지하려는 가정 하고 싶지 않아요Set , 아마도 가장 쉬운 방법은 다음과 같습니다

List<Customer> depdupeCustomers =
    new ArrayList<>(new LinkedHashSet<>(customers));

원래 목록을 변경하려면 :

Set<Customer> depdupeCustomers = new LinkedHashSet<>(customers);
customers.clear();
customers.addAll(dedupeCustomers);

java 8 업데이트
는 다음과 같이 배열 스트림을 사용할 수 있습니다.

Arrays.stream(yourArray).distinct()
                    .collect(Collectors.toList());

고객이 equals()계약을 이행합니까 ?

그것을 구현하지 않는 경우 equals()hashCode(), 다음 listCustomer.contains(customer)동일한 있는지 확인합니다 인스턴스가 이미 목록에있는 (- 메모리 주소 등 인스턴스가 나는 똑같은 개체를 의미한다). 찾고있는 것이 동일한 고객 (동일한 고객 이름 또는 고객 번호가있는 경우 동일한 고객 일 수 있음)이 이미 목록에 있는지 여부를 테스트하는 것이라면 재정 의하여 equals()확인해야합니다. 관련 필드 (예 : 고객 이름)가 일치하는지 여부.

참고 : 재정의 hashCode()하려는 경우 재정의 하는 것을 잊지 마십시오 equals()! 그렇지 않으면 HashMaps 및 기타 데이터 구조에 문제가 발생할 수 있습니다. 이것이 왜 좋은 커버리지 피하기 위해 어떤 함정, 조쉬 블로흐의 살펴 고려해 효과적인 자바 에 장을 equals()하고 hashCode()(링크는 단지 당신이 구현해야하는 이유에 대해 iformation 포함 hashCode()구현할 때 equals(),하지만 어떻게 재정에 대한 좋은 보험이를 equals()너무).

그런데 세트에 주문 제한이 있습니까? 그렇지 않은 경우이 문제를 해결하는 약간 더 쉬운 방법은 다음 Set<Customer>과 같이 사용하는 것입니다.

Set<Customer> noDups = new HashSet<Customer>();
noDups.addAll(tmpListCustomer);
return new ArrayList<Customer>(noDups);

세트는 중복을 허용하지 않기 때문에 중복을 멋지게 제거합니다. 그러나 이것은 명시적인 순서가 없기 tmpListCustomer때문에 에 적용된 순서를 잃게됩니다 HashSet(를 사용하여 해결할 수 TreeSet있지만 질문과 정확히 관련이 없습니다). 이것은 코드를 약간 단순화 할 수 있습니다.


목록 → 설정 → 목록 (구분)

모든 요소를 ​​a에 추가하기 만하면 Set요소가 반복되는 것을 허용하지 않습니다. 나중에 목록이 필요하면 나중에 새 ArrayList(theSet)생성자를 사용 theSet하십시오 (결과 집합은 어디에 있습니까 ).


나는 당신이 Customer.equals()제대로 (또는 전혀) 구현 하지 않았을 것이라고 생각합니다 .

List.contains()equals()매개 변수로 전달 된 객체와 동일한 요소가 있는지 확인 하는 데 사용합니다. 그러나 equals가치 ID가 아닌 물리적 ID 테스트 의 기본 구현입니다 . 따라서에서 덮어 쓰지 않은 경우 Customer상태가 동일한 두 개의 개별 고객 개체에 대해 false를 반환합니다.

다음은 구현 방법에equals 대한 핵심적인 세부 사항입니다 (그리고 hashCode그 쌍입니다-둘 중 하나를 구현해야하는 경우 실제로 항상 둘 다 구현해야 함). Customer 클래스를 보여주지 않았기 때문에 더 구체적인 조언을하기가 어렵습니다.

다른 사람들이 언급했듯이, 작업을 직접 수행하는 것보다 Set을 사용하는 것이 더 낫지 만, 그 경우에도 여전히 이러한 메서드를 구현해야합니다.


"contains"메소드는 목록에 Customer.equals (Object o)에서 true를 리턴하는 항목이 있는지 여부를 검색했습니다. Customer 또는 해당 상위 항목 중 하나에서 equals (Object)를 재정의하지 않은 경우 동일한 개체의 기존 항목 만 검색합니다. 이것이 당신이 원했던 것일 수 있으며,이 경우 코드가 작동해야합니다. 그러나 동일한 고객을 나타내는 두 개의 개체가없는 경우에는 equals (Object)를 재정 의하여 true를 반환해야합니다.

또한 List 대신 Set 구현 중 하나를 사용하면 중복 제거가 자동으로 더 빠르게 제공됩니다 (매우 작은 목록 이외의 경우). 여전히 동등한 코드를 제공해야합니다.

equals ()를 재정의 할 때 hashCode ()도 재정의해야합니다.


private void removeTheDuplicates(List<Customer>myList) {
    for(ListIterator<Customer>iterator = myList.listIterator(); iterator.hasNext();) {
        Customer customer = iterator.next();
        if(Collections.frequency(myList, customer) > 1) {
            iterator.remove();
        }
    }
    System.out.println(myList.toString());

}

두 가지 제안 :

  • Use a HashSet instead of an ArrayList. This will speed up the contains() checks considerably if you have a long list

  • Make sure Customer.equals() and Customer.hashCode() are implemented properly, i.e. they should be based on the combined values of the underlying fields in the customer object.


Nearly all of the above answers are right but what I suggest is to use a Map or Set while creating the related list, not after to gain performance. Because converting a list to a Set or Map and then reconverting it to a List again is a trivial work.

Sample Code:

Set<String> stringsSet = new LinkedHashSet<String>();//A Linked hash set 
//prevents the adding order of the elements
for (String string: stringsList) {
    stringsSet.add(string);
}
return new ArrayList<String>(stringsSet);

As others have mentioned, you are probably not implementing equals() correctly.

However, you should also note that this code is considered quite inefficient, since the runtime could be the number of elements squared.

You might want to consider using a Set structure instead of a List instead, or building a Set first and then turning it into a list.


The cleanest way is:

List<XXX> lstConsultada = dao.findByPropertyList(YYY);
List<XXX> lstFinal = new ArrayList<XXX>(new LinkedHashSet<GrupoOrigen>(XXX));

and override hascode and equals over the Id's properties of each entity


IMHO best way how to do it these days:

Suppose you have a Collection "dups" and you want to create another Collection containing the same elements but with all duplicates eliminated. The following one-liner does the trick.

Collection<collectionType> noDups = new HashSet<collectionType>(dups);

It works by creating a Set which, by definition, cannot contain duplicates.

Based on oracle doc.


The correct answer for Java is use a Set. If you already have a List<Customer> and want to de duplicate it

Set<Customer> s = new HashSet<Customer>(listCustomer);

Otherise just use a Set implemenation HashSet, TreeSet directly and skip the List construction phase.

You will need to override hashCode() and equals() on your domain classes that are put in the Set as well to make sure that the behavior you want actually what you get. equals() can be as simple as comparing unique ids of the objects to as complex as comparing every field. hashCode() can be as simple as returning the hashCode() of the unique id' String representation or the hashCode().


Using java 8 stream api.

    List<String> list = new ArrayList<>();
    list.add("one");
    list.add("one");
    list.add("two");
    System.out.println(list);
    Collection<String> c = list.stream().collect(Collectors.toSet());
    System.out.println(c);

Output:

Before values : [one, one, two]

After Values : [one, two]

ReferenceURL : https://stackoverflow.com/questions/2849450/how-to-remove-duplicates-from-a-list

반응형