ArrayListから繰り返し要素を削除するにはどうすればよいですか?


回答:


991

で重複が必要ない場合はCollectionCollection重複を許可するを使用している理由を考慮する必要があります。繰り返し要素を削除する最も簡単な方法は、コンテンツをSet(重複を許可しない)に追加し、次にをに追加SetすることArrayListです:

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

もちろん、これは内の要素の順序を破壊しArrayListます。


260
順序を保持したい場合は、LinkedHashSetも参照してください。
ボレー

3
:O(n)は、そのリストにあるオブジェクトに正しく定義されたequalsメソッドを持つことが重要(数値の問題なし)でのArrayListからすべての重複を見つける@Chetan 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; }
オンドレイBozek

4
良い習慣は、インターフェイスタイプを使用して変数を定義することであろうListSet(代わりに、実装タイプのArrayListHashSet、あなたの例のように)。
Jonik 2013

33
new HashSet(al)これを空にするために初期化する代わりに、を使用してこれをクリーンアップできaddAllます。
ashes999

1
重複するものを設定するルールを追加できますか?たとえば、Objectいくつかの値があり、そのうちの2つが繰り返される場合、それらを重複していると見なし(他の値は異なる場合があります)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
@マット:はい、それはそれを保証します。ドキュメントは言う:「このリンクされたリストは、要素がセット(挿入順)に挿入された順序である反復順序を定義する要素が再挿入セットにある場合、そのオーダーに影響を与えないことに注意してください。」。
abahgat

とても興味深い。ここでは別の状況があります。文字列をソートするのではなく、AwardYearSourceという別のオブジェクトをソートします。このクラスには、yearと呼ばれるint属性があります。そのため、年に基づいて重複を削除したいと思います。つまり、2010年が2回以上言及されている場合、そのAwardYearSourceオブジェクトを削除します。どうやってやるの?
WowBow

@WowBowたとえば、AwardYearSourceを保持するWrapperオブジェクトを定義できます。そして、このWrapperオブジェクトのequalsメソッドを、AwardYearSources年フィールドに基づいて定義します。次に、これらのWrapperオブジェクトでSetを使用できます。
Ondrej Bozek

@WowBowまたはComparable / Comparatorを実装する
shrini1000

134

Java 8の場合:

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

フィルタリングが適切に機能するためには、リストメンバーのhashCode-equals規約が尊重される必要があることに注意してください。


1
大文字と小文字を区別しない区別のためにこれをどのように行うのですか?
StackFlowed 2016

あなたができるリストの順番保存する必要がない場合は@StackFlowed addAllへをnew TreeSet<String>(String.CASE_INSENSITIVE_ORDER)。追加された最初の要素はセットに残りますので、リストに「犬」と「犬」がこの順序でTreeSet含まれている場合、「犬」が含まれます。順序を維持する必要がある場合は、答えの行の前に入れてくださいlist.replaceAll(String::toUpperCase);
ポール

1
このエラーが発生しました:互換性のないタイプ:List <Object>をList <String>に変換できません
Samir

これは一般に単純な解決策ですが、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));

注:挿入順序を維持したい場合はLinkedHashSetHashSet

Guavaの使用

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

重複させたくない場合は、の代わりにセットを使用してくださいList。をに変換するListにはSet、次のコードを使用できます。

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

本当に必要な場合は、同じ構造を使用してSetbackをに変換できますList


同様に、スレッドの下部で、カスタムオブジェクトの設定を使用しているところに回答を示しました。「連絡先」や「生徒」などのカスタムオブジェクトを持っている人がいる場合は、その答えを使用できます。
ムハンマドアディル2016年

問題は、要素に具体的にアクセスする必要がある場合に発生します。たとえば、オブジェクトを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ストリームは、重複する要素をリストから削除する非常に簡単な方法を提供します。個別の方法を使用します。都市のリストがあり、そのリストから重複を削除したい場合は、1行で実行できます-

 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は繰り返し項目のないリストです(YourClassが等しいことを表したいものに従って、equalsメソッドを持っていることを確認してください)。


この回答には2つの点が欠けています。1)ジェネリックを使用せず、生の型(のArrayList<T>代わりに使用する必要がありますArrayList)2)を使用することで、明示的なイテレータの作成を回避できますfor (T current : l1) { ... }Iterator明示的に使用したい場合でも、iteradorスペルミスです。
RAnders00

4
また、この実装は、線形時間で実行されるリンクされたハッシュセット実装と比較して、2次時間で実行されます。(。つまり、これが10,000要素と10個の要素、長いリスト上の1万倍で、リスト上の10倍の時間がかかるため、JDK 6の実装ArrayList.contains、JDK8の独自の実装は同じです。)
パトリック・M

21

HashSetまたは1つ以上の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 2013年

@maaartinusそのコードを試しましたか?例外は発生しません。また、かなり高速です。投稿する前にコードを試しました。
CarlJohn 2013年

4
そうです、リストの代わりに配列を反復するのではありません。しかし、それは地獄のように遅いです。数百万の要素で試してください。と比較してくださいImmutableSet.copyOf(lst).toList()
maaartinus 2013年

私がインタビューで尋ねられた質問に答えます..セットを使用せずにArrayListから繰り返し値を削除する方法。Thanx
Aniket Paul 2016

内部的にindexOflst、forループを使用して繰り返します。
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

おそらく少しやり過ぎですが、私はこの種の孤立した問題を楽しんでいます。:)

このコードは一時的な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();
        }
    }
}

マーカーインターフェイスを使用して、リストの統合ソリューションを提示します。

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、2009年

リストは、リストされている最初のメソッドのパラメーターとして完全に機能します。ただし、このメソッドは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
この実装作業は非常にうまくいきます。これの背後に問題はなく、このタスクでは1つのarraylistしか使用しません。したがって、この回答は完全に適切です。否定的なフィードバックを与える前に、テストケースを追加してすべての人が結果を理解できるようにしてください。ありがとうManash
Manash Ranjan Dakua

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()セットに変換してからリストに戻す代わりにを使用する利点はdistinct()、元のリストの順序を保持し、各要素の最初の出現を保持することです。これは、セットとリストの両方を使用して実装されます。

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;

元のリストをEclipseコレクションタイプに変換できない場合は、ListAdapterを使用して同じAPIを取得できます。

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

注:私はEclipseコレクションのコミッターです。


3

この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>を使用している場合。よろしくお願いします。

これは、セットやハッシュマップのような他のデータ構造を使用しない私のコードです

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年前の線形および対数線形の解があり、これも簡単な質問に対して、2次の解を投稿するのはなぜですか?
abarnert 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.