Persimpangan dan penyatuan Daftar Array di Jawa


130

Apakah ada metode untuk melakukannya? Saya mencari tetapi tidak dapat menemukannya.

Pertanyaan lain: Saya perlu metode ini sehingga saya bisa memfilter file. Beberapa ANDfilter dan beberapa ORfilter (seperti dalam teori himpunan), jadi saya perlu memfilter menurut semua file dan menyatukan / memotong ArrayLists yang menyimpan file-file tersebut.

Haruskah saya menggunakan struktur data yang berbeda untuk menyimpan file? Apakah ada hal lain yang akan menawarkan runtime yang lebih baik?


1
Jika Anda tidak ingin membuat daftar baru, Vector.retainAll (Vector) memotong vektor orignal Anda ke hanya persimpangan dengan vektor kedua.
user2808054

@ user2808054 mengapa Vector? Kelas itu telah putus asa sejak Java 1.2.
dimo414

@ dimo414 sebuah antarmuka yang saya gunakan (saya tidak punya pilihan) mengembalikan sesuatu sebagai vektor. Saya tidak tahu itu telah berkecil hati! Terima kasih atas informasinya .. Tidak disarankan oleh siapa? Saya belum melihat ada catatan tentang itu menjadi usang jadi ini adalah kejutan
user2808054

1
Dari Javadocs: " Pada platform Java 2 v1.2 ... disarankan untuk menggunakan ArrayList sebagai pengganti Vector. ". Satu-satunya waktu yang mungkin Anda perlukan Vectoradalah untuk interaksi lintas thread, tetapi ada struktur data yang lebih aman untuk kasus penggunaan tersebut juga. Lihat juga pertanyaan ini . Perpustakaan mana pun yang masih digunakan Vectorpada 2016 sangat mencurigakan menurut saya.
dimo414

@ dimo414 ini adalah perpustakaan IBM, haha! (Data api Lotus Domino). Terima kasih atas informasinya, sangat membantu
user2808054

Jawaban:


122

Berikut ini implementasi sederhana tanpa menggunakan perpustakaan pihak ketiga. Keuntungan utama lebih retainAll, removeAlldan addAllbahwa metode ini tidak mengubah input daftar asli ke metode.

public class Test {

    public static void main(String... args) throws Exception {

        List<String> list1 = new ArrayList<String>(Arrays.asList("A", "B", "C"));
        List<String> list2 = new ArrayList<String>(Arrays.asList("B", "C", "D", "E", "F"));

        System.out.println(new Test().intersection(list1, list2));
        System.out.println(new Test().union(list1, list2));
    }

    public <T> List<T> union(List<T> list1, List<T> list2) {
        Set<T> set = new HashSet<T>();

        set.addAll(list1);
        set.addAll(list2);

        return new ArrayList<T>(set);
    }

    public <T> List<T> intersection(List<T> list1, List<T> list2) {
        List<T> list = new ArrayList<T>();

        for (T t : list1) {
            if(list2.contains(t)) {
                list.add(t);
            }
        }

        return list;
    }
}

16
Anda dapat membuat daftar baru dengan elemen list1 dan kemudian memanggil retainAll, addAll methods
lukastymo

mengapa Anda menggunakan strictfp dalam solusi ini?
lukastymo

9
Harus menggunakan HashSetuntuk intersectionsehingga kinerja kasus rata-rata adalah O (n) bukan O (n ^ 2).
Zong

1
Posting ini dapat menggunakan pembaruan untuk menunjukkan manfaat API Java 8 Stream.
SME_Dev

Saya mendapatkan kesalahan Ketika saya mencoba menetapkan nilai ini -> Contoh: ArrayList <String> total total = (ArrayList <String>) persimpangan (list2, list1) ---> tidak dapat membuang java.util.arraylist ke java.util.arraylist < string>
delive

123

Koleksi (jadi ArrayList juga) memiliki:

col.retainAll(otherCol) // for intersection
col.addAll(otherCol) // for union

Gunakan implementasi Daftar jika Anda menerima pengulangan, Set implementasi jika Anda tidak:

Collection<String> col1 = new ArrayList<String>(); // {a, b, c}
// Collection<String> col1 = new TreeSet<String>();
col1.add("a");
col1.add("b");
col1.add("c");

Collection<String> col2 = new ArrayList<String>(); // {b, c, d, e}
// Collection<String> col2 = new TreeSet<String>();
col2.add("b");
col2.add("c");
col2.add("d");
col2.add("e");

col1.addAll(col2);
System.out.println(col1); 
//output for ArrayList: [a, b, c, b, c, d, e]
//output for TreeSet: [a, b, c, d, e]

3
Ada sunting yang disarankan bahwa penyatuan ini "tidak benar karena akan mengandung elemen umum dua kali" . Hasil edit disarankan untuk menggunakan HashSetgantinya.
Kos

5
Sebenarnya itu telah diedit, lihat: "Gunakan implementasi Daftar jika Anda menerima pengulangan, Set implementasi jika Anda tidak:"
lukastymo

7
Tidak, simpan semua bukan persimpangan untuk daftar. Di atas, semua elemen dalam col yang tidak ada di otherCol dihapus. Katakanlah otherCol adalah {a, b, b, c} dan col adalah {b, b, b, c, d}. Kemudian col diakhiri dengan {b, b, b, c} yang bukan merupakan perpotongan keduanya. Saya berharap itu {b, b, c}. Operasi berbeda sedang dilakukan.
demongolem

1
Saya juga tidak melihat bagaimana addAll()serikat untuk daftar; itu hanya menyatukan daftar kedua ke akhir yang pertama. Operasi gabungan akan menghindari penambahan elemen jika daftar pertama sudah mengandungnya.
dimo414

66

Posting ini cukup lama, tetapi tetap saja itu yang pertama muncul di google ketika mencari topik itu.

Saya ingin memberikan pembaruan menggunakan aliran Java 8 melakukan (pada dasarnya) hal yang sama dalam satu baris:

List<T> intersect = list1.stream()
    .filter(list2::contains)
    .collect(Collectors.toList());

List<T> union = Stream.concat(list1.stream(), list2.stream())
    .distinct()
    .collect(Collectors.toList());

Jika ada yang memiliki solusi yang lebih baik / lebih cepat, beri tahu saya, tetapi solusi ini adalah liner bagus yang dapat dengan mudah dimasukkan dalam metode tanpa menambahkan kelas / metode pembantu yang tidak perlu dan tetap menjaga keterbacaannya.


19
Ooof, ini mungkin bagus sekali, tapi butuh O (n ^ 2) waktu. Konversikan salah satu daftar menjadi Setlalu gunakan metode set contains. Tidak semua hal dalam hidup harus dilakukan dengan aliran.
dimo414

31
list1.retainAll(list2) - is intersection

serikat akan menjadi removeAlldan kemudian addAll.

Temukan lebih banyak di dokumentasi koleksi (ArrayList adalah koleksi) http://download.oracle.com/javase/1.5.0/docs/api/java/util/Collection.html


1
Keduanya retainAll()dan removeAll()merupakan operasi O (n ^ 2) pada daftar. Kita bisa melakukan yang lebih baik.
dimo414

1
Saya memilih tetapi sekarang saya punya pertanyaan. retainAlldari {1, 2, 2, 3, 4, 5} lebih dari {1, 2, 3} menghasilkan {1, 2, 2, 3}. Bukankah seharusnya {1, 2, 3} menjadi persimpangan?
GyuHyeon Choi

21

Serikat pekerja dan persimpangan hanya ditentukan untuk set, bukan daftar. Seperti yang Anda sebutkan.

Periksa perpustakaan jambu biji untuk filter. Juga jambu memberikan persimpangan dan persatuan yang nyata

 static <E> Sets.SetView<E >union(Set<? extends E> set1, Set<? extends E> set2)
 static <E> Sets.SetView<E> intersection(Set<E> set1, Set<?> set2)

12

Anda dapat menggunakan CollectionUtilsdari apache commons .


7
Jika seseorang menemukan jawaban ini agak terlalu pendek: 'CollectionUtils.containsAny' dan 'CollectionUtils.containsAll' adalah metode.
Sebastian

2
itu aneh bahwa CollectionUtils dari apache commons tidak mendukung obat generik
Vasyl Sarzhynskyi

7

Solusi yang ditandai tidak efisien. Ini memiliki kompleksitas waktu O (n ^ 2). Apa yang bisa kita lakukan adalah mengurutkan kedua daftar, dan mengeksekusi algoritma persimpangan seperti yang di bawah ini.

private  static ArrayList<Integer> interesect(ArrayList<Integer> f, ArrayList<Integer> s) { 
    ArrayList<Integer> res = new ArrayList<Integer>();

    int i = 0, j = 0; 
    while (i != f.size() && j != s.size()) { 

        if (f.get(i) < s.get(j)) {
            i ++;
        } else if (f.get(i) > s.get(j)) { 
            j ++;
        } else { 
            res.add(f.get(i)); 
            i ++;  j ++;
        }
    }


    return res; 
}

Yang ini memiliki kompleksitas O (n log n + n) yang ada di O (n log n). Serikat pekerja dilakukan dengan cara yang sama. Pastikan Anda membuat modifikasi yang sesuai pada pernyataan if-elseif-else.

Anda juga dapat menggunakan iterator jika Anda mau (saya tahu mereka lebih efisien dalam C ++, saya tidak tahu apakah ini benar di Jawa juga).


1
Tidak cukup generik, T mungkin tidak sebanding dan dalam beberapa kasus membandingkannya mahal ...
Boris Churzin

Tidak generik, saya setuju sepenuhnya. Membandingkan itu mahal? bagaimana Anda menyelesaikannya?
AJed

Sayangnya - akan lebih murah untuk melakukannya di O (n ^ 2) :) Untuk Bilangan solusi ini bagus ...
Boris Churzin

Sedihnya - Anda tidak menjawab pertanyaan saya. Biarkan saya ulangi, bagaimana O (n ^ 2) lebih baik diberikan fungsi perbandingan biaya c (n)?
AJed

1
Mengubah satu input ke set dan memanggil contains()dalam satu lingkaran (seperti saran Devenv) akan membutuhkan waktu O (n + m). Penyortiran tidak perlu rumit dan membutuhkan waktu O (n log n + m log n + n). Memang itu mengurangi waktu O (n log n), tapi itu masih lebih buruk daripada waktu linier, dan jauh lebih kompleks.
dimo414

4

Saya pikir Anda harus menggunakan Setuntuk menyimpan file jika Anda ingin melakukan persimpangan dan menyatukannya. Kemudian Anda dapat menggunakan Jambu 's Set kelas untuk melakukan union, intersectiondan penyaringan oleh Predicatejuga. Perbedaan antara metode ini dan saran lainnya adalah bahwa semua metode ini membuat pandangan malas tentang persatuan, persimpangan, dll. Dari dua set. Apache Commons membuat koleksi baru dan menyalin data ke sana. retainAllmengubah salah satu koleksi Anda dengan menghapus elemen dari itu.


4

Berikut ini cara Anda bisa melakukan persimpangan dengan stream (ingat bahwa Anda harus menggunakan java 8 untuk stream):

List<foo> fooList1 = new ArrayList<>(Arrays.asList(new foo(), new foo()));
List<foo> fooList2 = new ArrayList<>(Arrays.asList(new foo(), new foo()));
fooList1.stream().filter(f -> fooList2.contains(f)).collect(Collectors.toList());

Contoh untuk daftar dengan tipe yang berbeda. Jika Anda memiliki realtion antara foo dan bar dan Anda bisa mendapatkan bar-objek dari foo daripada Anda dapat memodifikasi aliran Anda:

List<foo> fooList = new ArrayList<>(Arrays.asList(new foo(), new foo()));
List<bar> barList = new ArrayList<>(Arrays.asList(new bar(), new bar()));

fooList.stream().filter(f -> barList.contains(f.getBar()).collect(Collectors.toList());

3
  • retainAll akan mengubah daftar Anda
  • Guava tidak memiliki API untuk Daftar (hanya untuk set)

Saya menemukan ListUtils sangat berguna untuk kasus penggunaan ini.

Gunakan ListUtils dari org.apache.commons.collections jika Anda tidak ingin mengubah daftar yang ada.

ListUtils.intersection(list1, list2)


3

Anda dapat menggunakan commons-collections4 CollectionUtils

Collection<Integer> collection1 = Arrays.asList(1, 2, 4, 5, 7, 8);
Collection<Integer> collection2 = Arrays.asList(2, 3, 4, 6, 8);

Collection<Integer> intersection = CollectionUtils.intersection(collection1, collection2);
System.out.println(intersection); // [2, 4, 8]

Collection<Integer> union = CollectionUtils.union(collection1, collection2);
System.out.println(union); // [1, 2, 3, 4, 5, 6, 7, 8]

Collection<Integer> subtract = CollectionUtils.subtract(collection1, collection2);
System.out.println(subtract); // [1, 5, 7]

2

Di Java 8, saya menggunakan metode pembantu sederhana seperti ini:

public static <T> Collection<T> getIntersection(Collection<T> coll1, Collection<T> coll2){
    return Stream.concat(coll1.stream(), coll2.stream())
            .filter(coll1::contains)
            .filter(coll2::contains)
            .collect(Collectors.toSet());
}

public static <T> Collection<T> getMinus(Collection<T> coll1, Collection<T> coll2){
    return coll1.stream().filter(not(coll2::contains)).collect(Collectors.toSet());
}

public static <T> Predicate<T> not(Predicate<T> t) {
    return t.negate();
}

1

Jika objek dalam daftar hashable (yaitu memiliki kode hash yang layak dan fungsi yang sama), pendekatan tercepat antara tabel kira-kira. size> 20 adalah untuk membangun HashSet untuk yang lebih besar dari dua daftar.

public static <T> ArrayList<T> intersection(Collection<T> a, Collection<T> b) {
    if (b.size() > a.size()) {
        return intersection(b, a);
    } else {
        if (b.size() > 20 && !(a instanceof HashSet)) {
            a = new HashSet(a);
        }
        ArrayList<T> result = new ArrayList();
        for (T objb : b) {
            if (a.contains(objb)) {
                result.add(objb);
            }
        }
        return result;
    }
}

1

Saya juga sedang mengerjakan situasi yang sama dan sampai di sini mencari bantuan. Akhirnya menemukan solusi saya sendiri untuk Array. ArrayList AbsentDates = ArrayList baru (); // Akan Menyimpan Array1-Array2

Catatan: Posting ini jika dapat membantu seseorang menjangkau halaman ini untuk mendapatkan bantuan.

ArrayList<String> AbsentDates = new ArrayList<String>();//This Array will store difference
      public void AbsentDays() {
            findDates("April", "2017");//Array one with dates in Month April 2017
            findPresentDays();//Array two carrying some dates which are subset of Dates in Month April 2017

            for (int i = 0; i < Dates.size(); i++) {

                for (int j = 0; j < PresentDates.size(); j++) {

                    if (Dates.get(i).equals(PresentDates.get(j))) {

                        Dates.remove(i);
                    }               

                }              
                AbsentDates = Dates;   
            }
            System.out.println(AbsentDates );
        }

1

Persimpangan dua daftar objek yang berbeda berdasarkan kunci umum - Java 8

 private List<User> intersection(List<User> users, List<OtherUser> list) {

        return list.stream()
                .flatMap(OtherUser -> users.stream()
                        .filter(user -> user.getId()
                                .equalsIgnoreCase(OtherUser.getId())))
                .collect(Collectors.toList());
    }

bagaimana dengan perbedaan yang ditetapkan antara 2 daftar itu?
jean

1
public static <T> Set<T> intersectCollections(Collection<T> col1, Collection<T> col2) {
    Set<T> set1, set2;
    if (col1 instanceof Set) {
        set1 = (Set) col1;
    } else {
        set1 = new HashSet<>(col1);
    }

    if (col2 instanceof Set) {
        set2 = (Set) col2;
    } else {
        set2 = new HashSet<>(col2);
    }

    Set<T> intersection = new HashSet<>(Math.min(set1.size(), set2.size()));

    for (T t : set1) {
        if (set2.contains(t)) {
            intersection.add(t);
        }
    }

    return intersection;
}

JDK8 + (Mungkin Kinerja Terbaik)

public static <T> Set<T> intersectCollections(Collection<T> col1, Collection<T> col2) {
    boolean isCol1Larger = col1.size() > col2.size();
    Set<T> largerSet;
    Collection<T> smallerCol;

    if (isCol1Larger) {
        if (col1 instanceof Set) {
            largerSet = (Set<T>) col1;
        } else {
            largerSet = new HashSet<>(col1);
        }
        smallerCol = col2;
    } else {
        if (col2 instanceof Set) {
            largerSet = (Set<T>) col2;
        } else {
            largerSet = new HashSet<>(col2);
        }
        smallerCol = col1;
    }

    return smallerCol.stream()
            .filter(largerSet::contains)
            .collect(Collectors.toSet());
}

Jika Anda tidak peduli dengan kinerja dan lebih suka kode yang lebih kecil, gunakan saja:

col1.stream().filter(col2::contains).collect(Collectors.toList());

0

Solusi akhir:

//all sorted items from both
public <T> List<T> getListReunion(List<T> list1, List<T> list2) {
    Set<T> set = new HashSet<T>();
    set.addAll(list1);
    set.addAll(list2);
    return new ArrayList<T>(set);
}

//common items from both
public <T> List<T> getListIntersection(List<T> list1, List<T> list2) {
    list1.retainAll(list2);
    return list1;
}

//common items from list1 not present in list2
public <T> List<T> getListDifference(List<T> list1, List<T> list2) {
    list1.removeAll(list2);
    return list1;
}

0

Pertama, saya menyalin semua nilai array ke dalam satu array lalu saya menghapus nilai duplikat ke dalam array. Baris 12, menjelaskan jika nomor yang sama terjadi lebih dari waktu kemudian masukkan nilai sampah tambahan ke posisi "j". Pada akhirnya, lintasi dari awal-akhir dan periksa apakah nilai sampah yang sama terjadi kemudian buang.

public class Union {
public static void main(String[] args){

    int arr1[]={1,3,3,2,4,2,3,3,5,2,1,99};
    int arr2[]={1,3,2,1,3,2,4,6,3,4};
    int arr3[]=new int[arr1.length+arr2.length];

    for(int i=0;i<arr1.length;i++)
        arr3[i]=arr1[i];

    for(int i=0;i<arr2.length;i++)
        arr3[arr1.length+i]=arr2[i];
    System.out.println(Arrays.toString(arr3));

    for(int i=0;i<arr3.length;i++)
    {
        for(int j=i+1;j<arr3.length;j++)
        {
            if(arr3[i]==arr3[j])
                arr3[j]=99999999;          //line  12
        }
    }
    for(int i=0;i<arr3.length;i++)
    {
        if(arr3[i]!=99999999)
            System.out.print(arr3[i]+" ");
    }
}   
}

1
Selamat Datang di Stack Overflow! Harap dicatat bahwa pertanyaannya adalah tentang ArrayList. Juga, saya khawatir implementasi khusus ini meninggalkan hal-hal yang diinginkan. Nilai 99999999, yang digunakan sebagai sentinel, dapat terjadi pada input. Akan lebih baik menggunakan struktur dinamis, seperti ArrayList, untuk menyimpan hasil serikat.
SL Barth - Reinstate Monica

1
Tolong jelaskan kode yang Anda berikan bukan hanya jawaban kode.
tmarois

Saya hanya memberikan petunjuk bahwa Anda harus memberikan nilai sampah
Ashutosh

Saya senang melihat Anda menambahkan penjelasan. Sayangnya, jawabannya sendiri masih buruk. Tidak ada alasan untuk menggunakan array. Anda harus menggunakan struktur dinamis seperti ArrayList. Jika (karena alasan tertentu) Anda harus menggunakan array, Anda harus mempertimbangkan menggunakan array Integerdaripada int. Maka Anda dapat menggunakan nullsebagai ganti "nilai sampah" Anda. "Nilai sampah" atau "nilai sentinel" biasanya merupakan ide yang buruk, karena nilai-nilai ini mungkin masih terjadi pada input.
SL Barth - Reinstate Monica

0

Setelah pengujian, inilah pendekatan persimpangan terbaik saya.

Kecepatan lebih cepat dibandingkan dengan Pendekatan HashSet murni. HashSet dan HashMap di bawah ini memiliki kinerja yang mirip untuk array dengan lebih dari 1 juta catatan.

Adapun pendekatan Java 8 Stream, kecepatan sangat lambat untuk ukuran array lebih besar dari 10k.

Semoga ini bisa membantu.

public static List<String> hashMapIntersection(List<String> target, List<String> support) {
    List<String> r = new ArrayList<String>();
    Map<String, Integer> map = new HashMap<String, Integer>();
    for (String s : support) {
        map.put(s, 0);
    }
    for (String s : target) {
        if (map.containsKey(s)) {
            r.add(s);
        }
    }
    return r;
}
public static List<String> hashSetIntersection(List<String> a, List<String> b) {
    Long start = System.currentTimeMillis();

    List<String> r = new ArrayList<String>();
    Set<String> set = new HashSet<String>(b);

    for (String s : a) {
        if (set.contains(s)) {
            r.add(s);
        }
    }
    print("intersection:" + r.size() + "-" + String.valueOf(System.currentTimeMillis() - start));
    return r;
}

public static void union(List<String> a, List<String> b) {
    Long start = System.currentTimeMillis();
    Set<String> r= new HashSet<String>(a);
    r.addAll(b);
    print("union:" + r.size() + "-" + String.valueOf(System.currentTimeMillis() - start));
}

0

retainAll () metode yang digunakan untuk menemukan elemen umum..ya; intersection list1.retainAll (list2)


-1

Jika Anda memiliki data di Sets, Anda bisa menggunakan Setskelas Guava .


-1

Jika nomor cocok dengan saya memeriksa itu terjadi pertama kali atau tidak dengan bantuan "indexOf ()" jika nomor cocok pertama kali kemudian cetak dan simpan ke dalam string jadi, bahwa ketika waktu berikutnya nomor yang sama cocok maka itu akan dimenangkan ' t mencetak karena karena kondisi "indexOf ()" akan salah.

class Intersection
{
public static void main(String[] args)
 {
  String s="";
    int[] array1 = {1, 2, 5, 5, 8, 9, 7,2,3512451,4,4,5 ,10};
    int[] array2 = {1, 0, 6, 15, 6, 5,4, 1,7, 0,5,4,5,2,3,8,5,3512451};


       for (int i = 0; i < array1.length; i++)
       {
           for (int j = 0; j < array2.length; j++)
           {
               char c=(char)(array1[i]);
               if(array1[i] == (array2[j])&&s.indexOf(c)==-1)
               {    
                System.out.println("Common element is : "+(array1[i]));
                s+=c;
                }
           }
       }    
}

}


2
Jangan hanya memposting kode sebagai jawaban, berikan sedikit penjelasan tentang apa yang Anda lakukan
Brandon Zamudio

ini adalah program pertama saya yang saya unggah
Ashutosh

2
Meskipun kode ini dapat membantu menyelesaikan masalah, kode ini tidak menjelaskan mengapa dan / atau bagaimana ia menjawab pertanyaan. Memberikan konteks tambahan ini akan secara signifikan meningkatkan nilai jangka panjangnya. Harap edit jawaban Anda untuk menambahkan penjelasan, termasuk batasan dan asumsi apa yang berlaku.
Toby Speight
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.