ArrayList'ten tekrarlanan öğeleri nasıl kaldırabilirim?


Yanıtlar:


991

A'da kopya istemiyorsanız, kopyalara Collectionneden Collectionizin veren bir kullandığınızı düşünmelisiniz . Yinelenen öğeleri kaldırmanın en kolay yolu, içeriği bir kopyaya Set(kopyalara izin vermeyecek şekilde) eklemektir ve ardından Setarkasına aşağıdakileri eklemektir ArrayList:

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

Tabii ki, bu, içindeki öğelerin sırasını yok eder ArrayList.


260
Siparişi korumak istiyorsanız, bkz. LinkedHashSet.
volley

3
@Chetan O (n) ArrayList tüm kopyaları bulmak, bu listede bulunan nesneler (sayılar için sorun yok) üzerinde doğru yöntem eşittir tanımlanmış olması önemlidir: 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

4
Arabirim türlerini Listve Set(uygulama türleri yerine ArrayListve HashSetörneğinizdeki gibi) kullanarak değişkenleri tanımlamak iyi bir uygulamadır .
Jonik

33
new HashSet(al)Boşaltmak ve çağırmak için başlatmak yerine bunu kullanarak temizleyebilirsiniz addAll.
ashes999

1
bana neyin kopya olduğunu ayarlamak için kurallar ekleyebilir miyim? Örneğin: Objecteğer iki değer yineleniyorsa birkaç değerim olduğunda bunları yineleniyor (diğer değerler farklı olabilir) ve kullanıyorum Set?
jean d'arme

290

Her ne kadar etkin ArrayListbir HashSetşekilde dönüştürmek yinelenenleri kaldırsa da, kampanya siparişini korumanız gerekiyorsa, bu varyantı kullanmanızı öneririm

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

Daha sonra, bir Listreferansı geri almanız gerekirse , dönüşüm oluşturucuyu tekrar kullanabilirsiniz.


10
LinkedHashSet birkaç kopyadan hangisinin listeden tutulacağı konusunda herhangi bir garanti veriyor mu? Örneğin, konum 1, 3 ve 5 orijinal listede yineleniyorsa, bu işlemin 3 ve 5'i kaldıracağını varsayabilir miyiz? Ya da belki 1 ve 3'ü kaldır? Teşekkürler.
Matt Briançon

16
@Matt: evet, bunu garanti ediyor. Dokümanlar ki: "Bu bağlantılı liste elemanları seti (ekleme sırası) yerleştirilmiştir sıradır yineleme sipariş, tanımlayan bir eleman yeniden sokulmuş dizi içine ise bu ekleme sırası etkilenmez dikkat edin.".
abahgat

Çok ilginç. Burada farklı bir durum var. Dize ama AwardYearSource adlı başka bir nesne sıralamak için çalışmıyorum. Bu sınıf yıl olarak adlandırılan bir int özelliğine sahiptir. Bu nedenle, yıllara göre kopyaları kaldırmak istiyorum. yani 2010 yılı birden fazla kez belirtilmişse, bu AwardYearSource nesnesini kaldırmak istiyorum. Bunu nasıl yapabilirim?
WowBow

@WowBow Örneğin AwardYearSource içeren Wrapper nesnesini tanımlayabilirsiniz. Ve bu Wrapper nesnelerini AwardYearSources yıl alanına göre eşittir yöntemini tanımlayın. Ardından Set'i bu Wrapper nesneleriyle kullanabilirsiniz.
Ondrej Bozek

@WowBow veya Karşılaştırılabilir / Karşılaştırıcıyı uygulayın
shrini1000

134

Java 8'de:

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

Filtrelemenin düzgün çalışması için liste üyeleri için hashCode-eşittir sözleşmesine uyulması gerektiğini lütfen unutmayın .


1
Büyük / küçük harfe duyarlı olmayan durumlar için bunu nasıl yapabilirim?
StackFlowed

Eğer yapabilirsiniz listenin düzeni korumak için gerekmiyorsa @StackFlowed addAlliçin new TreeSet<String>(String.CASE_INSENSITIVE_ORDER). Eklenen ilk öğe kümede kalacaktır, böylece listeniz "Köpek" ve "köpek" içeriyorsa (bu sırayla) TreeSet"Köpek" içerecektir. Eğer emrin korunması gerekiyorsa, cevaptaki satırdan önce list.replaceAll(String::toUpperCase);.
Paul

1
Bu hatayı alıyorum: uyumsuz türler: Liste <Object> Liste <String>
Samir

Bu genel olarak basit bir çözümdür ancak yinelemeleri int [] dizisinden nasıl kaldırırsınız?
Nooby Programcı

56

Şöyle bir listemiz olduğunu varsayalım String:

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

Ardından, yinelenen öğeleri birden çok şekilde kaldırabiliriz.

Java 8'den önce

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

Not: Kampanya siparişini korumak istiyorsak LinkedHashSet,HashSet

Guava'yı kullanma

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

Java 8'i kullanma

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

Not: biz sonucu toplamak istediğiniz durumda belirli liste uygulaması ör LinkedListo zaman yukarıdaki örneği olarak değiştirebilirsiniz:

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

parallelStreamYukarıdaki kodda da kullanabiliriz , ancak beklenen performans avantajları sağlamayabilir. Daha fazla bilgi için bu soruyu kontrol edin .


Yah, önceki yorumlarımı yazdığımda, parallel streamsher zaman daha iyi performans verecek bir izlenim içindeydim. Ama bu bir efsane. Daha sonra paralel akışların kullanılması gereken bazı senaryolar olduğunu öğrendim. Bu senaryoda paralel akışlar daha iyi bir performans vermeyecektir. ve evet paralel akışlar bazı durumlarda istenen sonuçları vermeyebilir. List<String> deDupStringList3 = stringList.stream().map(String::toLowerCase).distinct().collect(Collectors.toList());bu durumda uygun çözüm olmalıdır
Diablo

53

Kopya istemiyorsanız, yerine bir Küme kullanın List. Bir dönüştürmek için Listbir için Setaşağıdaki kodu kullanabilirsiniz:

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

Gerçekten gerekliyse, aynı yapıyı bir Setgeri dönüştürmek için kullanabilirsiniz List.


Benzer şekilde iş parçacığının alt kısmında, Set for Custom Object kullandığım bir cevap verdim. Birisinin "Kişi" veya "Öğrenci" gibi özel bir nesnesi varsa, bu yanıtı benim için iyi çalışır.
Muhammed Adil

Sorun, bir öğeye özel olarak erişmeniz gerektiğinde ortaya çıkar. Örneğin, bir nesneyi Android'de bir liste öğesi görünümüne bağlarken, ona dizin verilir. Yani Setburada kullanılamaz.
TheRealChx101

Liste bir nesne listesi olduğunda buna nasıl
yaklaşabilirim

28

Ayrıca bu şekilde yapabilir ve düzeni koruyabilirsiniz:

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

Bu bir ArrayList yinelenen kaldırmanın en iyi yolu olduğunu düşünüyorum. Kesinlikle önerilir. Cevap için @Nenad'a teşekkür ederim.
ByWaleed

25

Java 8 akışları, yinelenen öğeleri bir listeden kaldırmak için çok basit bir yol sağlar. Farklı yöntem kullanarak. Bir şehirler listemiz varsa ve bu listeden kopyaları kaldırmak istiyorsak, bu işlem tek bir satırda yapılabilir -

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

Bir arraylistten yinelenen öğeler nasıl kaldırılır


25

Liste sıralamanızı etkilemeyen bir yol:

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 orijinal listedir ve l2 yinelenen öğeler içermeyen listedir (Sınıfınızın eşitlik için ayakta durmak istediğiniz şeye göre eşittir yöntemine sahip olduğundan emin olun)


Bu cevap iki şeyden yoksundur: 1) Jenerikler kullanmaz, ancak ham türleri ( ArrayList<T>yerine kullanılmalıdır ArrayList) 2) a kullanarak açık yineleyici oluşturmaktan kaçınılabilir for (T current : l1) { ... }. IteratorAçıkça kullanmak iteradoristeseniz bile yanlış yazılmıştır.
RAnders00

4
Ve bu uygulama, doğrusal zamanda çalışan bağlantılı karma küme uygulamasına kıyasla ikinci dereceden bir sürede çalışır. (yani bu, 10 öğeli bir listede 10 kat, 10.000 öğeli bir listede 10.000 kat daha uzun sürer. ArrayList için JDK 6 uygulaması , JDK8 impl'si aynıdır.)
Patrick M

21

HashSet veya bir arraylist kullanmadan kopyaları arraylist'ten çıkarmak mümkündür .

Bu kodu deneyin ..

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

Çıktı

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

Yavaş ve bir ConcurrentModificationException alabilirsiniz.
maaartinus

@maaartinus Bu kodu denediniz mi? Herhangi bir istisna oluşturmaz.Ayrıca oldukça hızlıdır. Göndermeden önce kodu denedim.
CarlJohn

4
Haklısın, dizi yerine diziyi yinelediğin gibi değil. Ancak, cehennem gibi yavaş. Birkaç milyon elemanla deneyin. İle karşılaştırın ImmutableSet.copyOf(lst).toList().
maaartinus

Röportajda sorulan soruyu cevaplıyor .. Setler kullanmadan bir ArrayList'ten tekrarlanan değerler nasıl kaldırılır. Thanx
Aniket Paul

Dahili olarak, for döngüsünü kullanarak indexOfyineler lst.
Patrick M


19

bu sorunu çözebilir:

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
Bu çözümü daha çok sevdim.
Tushar Gogna

12

Muhtemelen biraz abartıldım, ama bu tür bir izole sorunun tadını çıkarıyorum. :)

Bu kod geçici bir Küme kullanır (benzersizlik denetimi için), ancak öğeleri doğrudan orijinal listenin içinde kaldırır. Bir ArrayList içindeki öğenin kaldırılması çok sayıda dizi kopyalamaya neden olabileceğinden, remove (int) yönteminden kaçınılır.

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

Biz oradayken, LinkedList için bir sürüm (çok daha güzel!):

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

Liste için birleştirilmiş bir çözüm sunmak için işaretleyici arabirimini kullanın:

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

DÜZENLEME: Sanırım jenerikler burada gerçekten bir değer katmıyor .. Ah güzel. :)


1
Parametrede neden ArrayList kullanılır? Neden sadece Liste değil? Bu işe yaramayacak mı?
Shervin Asgari

Liste, listelenen ilk yöntem için kesinlikle parametre içi olarak çalışacaktır . Ancak yöntem, ArrayList gibi rasgele bir erişim listesiyle kullanım için optimize edilmiştir , bu nedenle bir LinkedList iletilirse düşük performans elde edersiniz. Örneğin, LinkedList'te n: th öğesinin ayarlanması O (n) zaman alırken, rasgele erişim listesinde (ArrayList gibi) n: th öğesinin ayarlanması O (1) zaman alır. Yine de, bu muhtemelen aşırıdır ... Bu tür özel bir koda ihtiyacınız varsa, umarım izole bir durumda olacaktır.
volley

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

Bu uygulama, son j--
neo7

1
Bu uygulama çalışması çok iyi. Bunun arkasında bir sorun yok ve bu görev için sadece bir arraylist kullanıyorum. Bu yüzden bu cevap tamamen iyidir. Negatif geri bildirim vermeden önce her birinin sonucu anlayabilmesi için test çantası da eklemelisiniz. Manash
Manash Ranjan Dakua

5

Bir üçüncü taraf kitaplığı kullanmak isteyen iseniz, yöntemi kullanabilirsiniz distinct()yılında Eclipse Koleksiyonları (eski GS Koleksiyonları).

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

Bir Kümeye distinct()dönüştürmek ve sonra tekrar Listeye dönüştürmek yerine kullanmanın avantajı distinct(), orijinal Listenin sırasını koruyarak her öğenin ilk oluşumunu koruyabilmesidir. Hem Set hem de Liste kullanılarak uygulanır.

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;

Orijinal Listenizi Eclipse Collections türüne dönüştüremiyorsanız, aynı API'yı almak için ListAdapter kullanabilirsiniz.

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

Not: Eclipse Collections için bir komisyoncuyum.


3

Bu üç kod satırı, çoğaltılan öğeyi ArrayList'ten veya herhangi bir koleksiyondan kaldırabilir.

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

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

2

ArrayList'i doldururken, her öğe için bir koşul kullanın. Örneğin:

    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} dizisi alacağız


2

Siparişinizi korumak istiyorsanız LinkedHashSet'i kullanmak en iyisidir . Çünkü bu listeyi yineleyerek bir ekleme sorgusuna iletmek isterseniz, sıra korunacaktır.

Bunu dene

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

Bu dönüşüm, bir Set döndürmek istediğinizde bir Set döndürmek istediğinizde çok yardımcı olacaktır.


2

Kod:

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

Not: Kesinlikle, bellek ek yükü olacaktır.


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 hile yapacak.

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

// çıktı: 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

Bu, Özel Nesneler listeniz için kullanılır

   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

iç içe döngü aşağıdaki gibi kullanabilirsiniz:

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

Daha önce de belirtildiği gibi, öğelerin tekliğinden emin olmak için List yerine Set arabirimini uygulayan bir sınıf kullanmalısınız. Elemanların sırasını korumak zorunda kalırsanız, SortedSet arayüzü kullanılabilir; TreeSet sınıfı bu arabirimi uygular.


1

Model tipini kullanıyorsanız List <T> / ArrayList <T> yazın. Umarım size yardımcı olur.

İşte benim kod set veya hashmap gibi başka bir veri yapısı kullanmadan

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

Yinelenenleri ArrayList'ten kaldırmak istiyorsanız, aşağıdaki mantığı bulmak anlamına gelir,

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
Zaten 2 yıllık doğrusal ve log-lineer çözümlere sahip olan ve aynı zamanda daha basit olan bir soruya neden ikinci dereceden bir çözüm yollasın?
abarnert
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.