JavaでのArrayListの共通部分と結合


130

そうする方法はありますか?探していましたが見つかりませんでした。

別の質問:ファイルをフィルタリングできるように、これらのメソッドが必要です。一部はANDフィルターであり、一部はORフィルター(集合論のように)なので、すべてのファイルとそれらのファイルを保持する結合/交差するArrayListsに従ってフィルター処理する必要があります。

ファイルを保持するために別のデータ構造を使用する必要がありますか?より良いランタイムを提供するものは他にありますか?


1
新しいリストを作成したくない場合、Vector.retainAll(Vector)は元のベクトルを2番目のベクトルとの交点のみにトリミングします。
user2808054

@ user2808054なぜVectorですか?そのクラスはJava 1.2以降推奨されていません。
dimo414 2016年

@ dimo414私が使用しているインターフェース(オプションはありません)は、ベクトルとして物を返します。それが落胆したことを知りませんでした!情報をありがとう..誰にがっかり?私は、これは驚きであるので、それが廃止さについてのノートを見ていない
user2808054

1
Javadocsから:「Java 2プラットフォームv1.2以降では、Vectorの代わりにArrayListを使用することをお勧めします。」必要になる可能Vectorがあるのはスレッド間相互作用の場合のみです、それらのユースケースにも安全なデータ構造があります。この質問も参照してください。Vector2016年にまだ使用されているライブラリは、私の考えでは非常に疑わしいものです。
dimo414 2016年

@ dimo414それはIBMライブラリです、ハハ!(Lotus DominoデータAPI)。情報をありがとう、とても役に立ちました
user2808054

回答:


122

以下は、サードパーティのライブラリを使用しない単純な実装です。主な利点を超えるretainAllremoveAll及びaddAllこれらのメソッドは、メソッドに、元のリストの入力を変更しないことです。

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
list1要素で新しいリストを作成し、retainAll、addAllメソッドを呼び出すことができます
lukastymo

このソリューションでstrictfpを使用する理由
lukastymo 2011年

9
HashSetforを使用して、intersectionケースの平均パフォーマンスがO(n ^ 2)ではなくO(n)になるようにします。
Zong

1
この投稿では、更新を使用してJava 8 Stream APIの利点を示すことができます。
SME_Dev

この値を割り当てようとするとエラーが発生する->例:ArrayList <String> total total =(ArrayList <String>)intersection(list2、list1)---> java.util.arraylistをjava.util.arraylist <にキャストできませんstring>
2016

123

コレクション(したがってArrayListも)には次のものが含まれます。

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

繰り返しを受け入れる場合はList実装を使用し、そうでない場合はSet実装を使用します。

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
この共用体は、「共通の要素が2回含まれるため、正しくない」との提案がありました。HashSet代わりにを使用することをお勧めします。
Kos

5
実際に編集されました。「繰り返しを受け入れる場合はList実装を、そうでない場合はSet実装を使用してください」
lukastymo

7
いいえ、retainAllはリストの交差ではありません。上記では、otherColにないcolのすべての要素が削除されます。otherColが{a、b、b、c}で、colが{b、b、b、c、d}であるとします。次に、colは{b、b、b、c}で終わりますが、これは厳密には2つの交点ではありません。それは{b、b、c}であると期待します。別の操作が実行されています。
デーモンゴレム2016年

1
またaddAll()、リストの結合がどのように表示されるかもわかりません。2番目のリストを最初のリストの最後に連結するだけです。ユニオン操作では、最初のリストにすでに要素が含まれている場合、要素の追加が回避されます。
dimo414 2016年

66

この投稿はかなり古いですが、それでも、そのトピックを探しているときにgoogleで最初にポップアップ表示されました。

(基本的に)同じことを1行で行うJava 8ストリームを使用して更新を行いたい:

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

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

誰かがより良い/より速い解決策を持っている場合は私に知らせてください、しかしこの解決策は不必要なヘルパークラス/メソッドを追加せずにメソッドに簡単に含めることができ、読みやすさを維持できる素晴らしいワンライナーです。


19
うーん、いいワンライナーかもしれませんが、O(n ^ 2)時間かかります。リストの1つをに変換してからSet、セットのcontainsメソッドを使用します。人生のすべてがストリームで行われる必要はありません。
dimo414 2016年

31
list1.retainAll(list2) - is intersection

労働組合はremoveAll、その後になりaddAllます。

コレクションのドキュメントで詳細を確認してください(ArrayListはコレクションです) http://download.oracle.com/javase/1.5.0/docs/api/java/util/Collection.html


1
retainAll()removeAll()はどちらもリストに対するO(n ^ 2)操作です。私たちはもっとうまくやることができます。
dimo414 2016年

1
賛成票を投じましたが、質問があります。retainAll{1、2、2、3、4、5}が{1、2、3}を超えると、{1、2、2、3}になります。交差点になるのは{1、2、3}ではないでしょうか?
GyuHyeon Choi 2017

21

ユニオンと交差は、リストではなくセットに対してのみ定義されます。あなたが言ったように。

フィルターについては、グアバライブラリを確認してください。また、グアバは実際の交差点と労働組合を提供します

 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)


7

マークされたソリューションは効率的ではありません。O(n ^ 2)時間の複雑さがあります。私たちにできることは、両方のリストをソートし、以下のような交差アルゴリズムを実行することです。

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

これはO(n log n)にあるO(n log n + n)の複雑さを持っています。結合は同様の方法で行われます。if-elseif-elseステートメントに適切な変更を加えていることを確認してください。

必要に応じてイテレータを使用することもできます(C ++ではイテレータの方が効率的ですが、Javaでも同様です)。


1
Tは一般的ではありません。Tは比較可能ではない場合があり、場合によっては比較にコストがかかります...
Boris Churzin

一般的ではない、私は完全に同意します。比較は高いですか?どのように解決しますか?
AJed June

悲しいことに-O(n ^ 2)で行う方が安くなる:)数値の場合、このソリューションは適切です...
Boris Churzin

悲しいことに-あなたは私の質問に答えませんでした。言い換えると、コストc(n)の比較関数を考えると、O(n ^ 2)はどのように優れているのでしょうか。
2016年

1
1つの入力をセットに変換contains()し、ループで呼び出す(Devenvが提案するように)には、O(n + m)時間かかります。ソートは不必要に複雑であり、O(n log n + m log n + n)時間かかります。これはO(n log n)時間に短縮されますが、それでも線形時間よりも悪く、はるかに複雑です。
dimo414 2016年

4

Setファイルの交差と結合を行う場合は、ファイルを保持するためにa を使用する必要があると思います。次に、GuavaSetsクラスを使用してunionintersectionでフィルタリングPredicateできます。これらのメソッドと他の提案の違いは、これらのメソッドのすべてが2つのセットの和集合、交差などの遅延ビューを作成することです。Apache Commonsは新しいコレクションを作成し、そこにデータをコピーします。retainAll要素を削除してコレクションの1つを変更します。


4

以下は、ストリームとの共通部分を作成する方法です(ストリームにはJava 8を使用する必要があることに注意してください)。

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

タイプの異なるリストの例。fooとbarの間に関係があり、ストリームを変更するよりもfooからbarオブジェクトを取得できる場合:

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はリストを変更します
  • グアバにはリスト用のAPIがありません(セット用のみ)

ListUtilsは、この使用例に非常に役立つことがわかりました。

既存のリストを変更したくない場合は、org.apache.commons.collectionsのListUtilsを使用してください。

ListUtils.intersection(list1, list2)


3

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

Java 8では、次のような単純なヘルパーメソッドを使用します。

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

リスト内のオブジェクトがハッシュ可能である場合(つまり、適切なhashCodeおよびequals関数がある場合)、テーブル間の最速のアプローチは サイズ> 20は、2つのリストのうち大きい方のHashSetを作成するためのものです。

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

私も同様の状況に取り組んでおり、助けを求めてここにたどり着きました。結局、自分の配列のソリューションを見つけることになりました。ArrayList AbsentDates = new ArrayList(); // Array1-Array2を格納します

注:誰かがこのページにアクセスして助けを得ることができる場合は、これを投稿してください。

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

共通キーに基づく異なるオブジェクトの2つのリストの交差-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());
    }

これら2つのリストの違いはどうですか?
ジャン

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 +(おそらく最高のパフォーマンス)

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

パフォーマンスを気にせず、より小さなコードを好む場合は、以下を使用してください:

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

0

最終的解決:

//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

最初に、配列のすべての値を単一の配列にコピーしてから、重複する値を配列から削除しています。12行目、同じ数が時間よりも多く発生するかどうかを説明し、余分なガベージ値を "j"の位置に配置します。最後に、開始から終了までトラバースし、同じガベージ値が発生するかどうかを確認してから破棄します。

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
Stack Overflowへようこそ!問題はArrayListに関するものであることに注意してください。また、私はこの特定の実装が望ましいことを残していると思います。センチネルとして使用される値99999999が入力で発生する可能性があります。ArrayListユニオンの結果を保存するには、などの動的構造を使用する方が良いでしょう。
SLバース-モニカを2017年

1
コードの解答ではなく、提示したコードについて説明してください。
tmarois 2017年

私はあなたがガベージバリューを入れなければならない手がかりを与えています
アシュトシュ

あなたが説明を追加してくれてうれしいです。残念ながら、答え自体はまだ悪いです。配列を使用する理由はありません。ArrayListのような動的構造を使用する必要があります。(何らかの理由で)配列を使用する必要がある場合は、Integerではなくの配列を使用することを検討してくださいint。その後null、「ガベージバリュー」の代わりに使用できます。「ガベージ値」または「センチネル値」は、入力でまだ発生する可能性があるため、通常はお勧めできません。
SLバース-モニカ

0

テスト後、これが私の最善の交差点アプローチです。

純粋なHashSetアプローチと比較して高速です。以下のHashSetとHashMapは、100万を超えるレコードを持つ配列に対して同様のパフォーマンスを発揮します。

Java 8 Streamアプローチに関しては、配列サイズが10kより大きい場合、速度はかなり遅くなります。

これがお役に立てば幸いです。

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


-1

セットにデータがある場合は、グアバのSetsクラスを使用できます。


-1

私がチェックしているよりも数値が一致する場合、「indexOf()」の助けを借りてそれが最初に発生するかどうかが確認されます。 「indexOf()」条件がfalseになるため、印刷します。

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
回答としてコードを投稿するだけでなく、何をしているのかについて少し説明してください
Brandon Zamudio

それは私がアップロードした私の最初のプログラムです
アシュトッシュ2017年

2
このコードは問題の解決に役立つ可能性がありますが、なぜまたはどのように質問に回答するかについては説明していません。この追加のコンテキストを提供すると、その長期的な価値が大幅に向上します。回答を編集して、適用される制限や前提条件などの説明を追加してください。
Toby Speight 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.