2010-12-01 3 views
6

ArrayLst를 검색하여 동일한 항목을 모두 삭제하려고합니다. 예를 들어Java에서 ArrayList 수정

내 목록이 있다면 : 사과, 오렌지, 바나나, 배, 복숭아, 오렌지,

다음 "오렌지"가 삭제 될 것입니다 (두 차례 나오는).

순진, 내가 시도 : 나는 단어가 동일한 경우 (lastIndexOf에서도 (userword)) .remove하는 방법을 썼다

for(String word : userlist){ 

for(String otherword : userlist){ 

... 
} 
} 

자신의 인덱스가 다릅니다.

이것은 예외 후에 예외로 이어지고, 나는 그것이 잘못되어 가고있는 것을 반복하면서 목록을 조작하고 있다는 것을 빨리 알게되었다.

그래서
ArrayList<String> copylist = userlist; 

for(String word : copylist){ 

    for(String otherword : copylist){ 

    if(word.equalsIgnoreCase(otherword) 
      && copylist.lastIndexOf(word)!=copylist.lastIndexOf(otherword)){ 

userlist.remove(userlist.lastIndexOf(word)); 
userlist.remove(userlist.lastIndexOf(otherword)); 
    } 

    } 
    } 

그래서 난이 시도 목록의 복사본을 만들하기로 결정하고, 비슷한 문제가 있었다. 특히 ConcurrentModificationException. 내가 조정할 수 없으면, 자바에서 작업하기 위해서는 머리 속에있는 것이 꽤 쉬운 과정이어야한다. 도와주세요.

답변

10

현재이 목록의 사본을 전혀 만들지 않습니다. 동일한 목록에 대한 참조가있는 새 변수를 선언하고 있습니다. 목록의 사본을 만들려면 사용

ArrayList<String> copyList = new ArrayList<String>(userList); 

그러나, 나는 다른 방법을 건의 할 것입니다 :

ArrayList<String> wordsToRemove = new ArrayList<String>(); 
Set<String> seenWords = new HashSet<String>(); 

for (String word : userList) 
{ 
    if (!seenWords.add(word)) 
    { 
     wordsToRemove.add(word); 
    } 
} 

for (String word : wordsToRemove) 
{ 
    // Keep removing it until it doesn't exist any more 
    while (userList.remove(word)) {} 
} 

그러나, 사건을 무시하지 않습니다. 그렇게하려면, 당신은 조금 더 똑똑 할 필요가 :

Set<String> wordsToRemove = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); 
Set<String> seenWords = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); 

for (String word : userList) 
{ 
    if (!seenWords.add(word)) 
    { 
     wordsToRemove.add(word); 
    } 
} 

// Now we know the words we don't want, step through the list again and 
// remove them (case-insensitively, as wordsToRemove is case-insensitive) 
for (Iterator<String> iterator = userList.iterator(); it.hasNext() ;) 
{ 
    if (wordsToRemove.contains(word)) 
    { 
     iterator.remove(); 
    } 
} 
+1

절대로 잠들지 않습니까? :( – musiKk

+4

@ musiKk : 참조 http://meta.stackexchange.com/questions/555/ –

+1

@MusiKk 또한 http://meta.stackexchange.com/questions/9134/jon-skeet-facts를 참조하십시오. –

1
ArrayList<String> copylist = userlist; 

이 줄은 copylist하는 기준 사용자 목록을 할당하고이를 새로운 ArrayList를 작성하지 않습니다. 그것은 같은 arraylist를 가리 킵니다. 새 목록을 만들려면 간단한 방법은 항목이 이미 새 목록에 있는지 여부를 확인한 후 새 목록을 만들고이 새 목록에 항목을 계속 추가하는 것입니다.

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

foreach(String item in userList) { 
    if(newList.contains(item)==false) 
    { 
      newList.add(item); 
    } 
} 
+0

그건 중복이없는리스트로 끝날 것입니다. 그러나 예를 들어 여전히 "오렌지색"의 인스턴스가 하나 남아 있습니다. –

+0

'foreach (userList에있는 문자열 항목)'이것은 자바가 아닙니다. 당신은'for (String item : userList) '을 의미합니다. –

+0

@ S.P.Floyd, foreach. 나는 Java를 1 년 전에 떠났다. .. C#에서 지금 foreach에 익숙하다. .. – Shekhar

1

잘 알려진 문제점은 반복되는 컨테이너를 수정할 수 없다는 것입니다. 트릭 해결하기는 반복자의 방법 제거의 사용이다 :

Iterator<String> tblIter = array.iterator(); 
    while (tblIter.hasNext()) { 
     String entry = tblIter.next(); 
     if(entry.equals(.....)) 
     { 
      ... 
      tblIter.remove(); 
     } 
    } 
+0

두 인스턴스는 반드시 제거해야한다. 이게 효과가 있을지 모르겠다. 답변 주셔서 감사 드리며, 한번 시도해 보겠습니다. –

2

당신이 컬렉션을 반복하는 동안 요소를 당신이 반복자와는, Iterator.remove()

를 사용해야하지만 내가 원하는 제거하려면 당신에게 더 쉬운 해결책을 제안하십시오 : 당신의 명부를 세트로 끼워 넣으십시오.

List<String> mylist = new ArrayList<String>(); 
// some initialization: there are duplicates 

Set<String> myset = new HashSet<String>(mylist); // no duplicates here. 

컬렉션이 있으므로 컬렉션을 계속 사용할 수 있으며 반복 할 수 있습니다.하지만 랜덤 액세스 목록을 다시 작성해야하는 경우 :

newlist = new ArrayList<String>(myset); 

해시 결과 집합의 요소 순서는 "임의"가됩니다. 원래 순서를 유지하려면 HashSet 대신 LinkedHashSet을 사용하십시오. 어떻게 /에서 제어 할 수없는 경우, 다른 한편으로는

add(element) 
{ 
    if arrayList.contains(element) 
     arrayList.remove(arrayList.indexOf(element)) 

    else 
     arrayList.add(element) 
} 

:

+0

두 가지를 모두 제거하는 대신 하나의 "오렌지색"인스턴스로 끝납니다. 아이디어는 복제 된 모든 값의 사본을 모두 제거하는 것입니다. –

+0

제가 이해하기에, 그는 둘 다 제거 된 복제물을 원합니다. 또한 LinkedHashSet을 사용하여 순서를 유지하고 기존 목록 (list.clear(); list.addAll (set);)을 다시 사용할 수 있습니다. – sfussenegger

0

는 데이터를 추가하는 방법에 대한 제어가있는 경우,이 같은 일을 자신의 "추가"방법을 만들 수 있습니다 데이터가 추가되면 루프를 수행 할 수 있고 위와 비슷한 논리가 있습니다. 적절한 방법은 here을보십시오.

+0

감사합니다! 사실 나는 그것을 시도해 보았다. 현재의 솔루션은 매우 유사합니다. 프로그램에 많은 것을 추가하면 매우 어색하고 잘 작동하지 않을 수 있습니다. 나는 그것을하는 가장 좋은 방법을 알고 싶었다. –

4
import java.util.ArrayList; 
import java.util.HashSet; 
import java.util.List; 
import java.util.Set; 


public class Test { 
    public static void main(String[] args) { 
     List<String> a = new ArrayList<String>(); 
     a.add("apple"); 
     a.add("orange"); 
     a.add("banana"); 
     a.add("pear"); 
     a.add("peach"); 
     a.add("orange"); 
     System.out.println(a); 
     System.out.println(getSingleWordList(a)); 
    } 
    private static List<String> getSingleWordList(List<String> list) 
    { 
     Set<String> uniques = new HashSet<String>(); 
     Set<String> dups = new HashSet<String>(); 

     for (String a : list) 
      if (!uniques.add(a)) 
       dups.add(a); 


     uniques.removeAll(dups); 

     return new ArrayList<String>(uniques); 
    } 
} 

OUTPUT은 목적이 중복 요소가없는 콜렉션 인 경우

Input = [apple, orange, banana, pear, peach, orange]

Output = [pear, apple, banana, peach]

+3

그건 좋은거야. 나는 그것을 좋아한다. 주문 보존이 필요한 경우'LinkedHashSet'을 사용하십시오. –

+0

내가 아는 바에 따르면 그는 새 목록이 아닌 이전 목록을 변경하려고합니다. 따라서 나는 당신의 리턴 라인을'list.clear(); list.addAll (uniques);' – sfussenegger

0

, Set를 목록보다 더 적합한 지 여부를 고려한다.