web-dev-qa-db-ja.com

JavaのArrayListsの交差と結合

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

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

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

118
yotamoo

これは、サードパーティのライブラリを使用しない単純な実装です。 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;
    }
}
112
adarshr

コレクション (そのためArrayListも):

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

繰り返しを受け入れる場合はリスト実装を使用し、そうでない場合はセット実装を使用します。

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]
113
lukastymo

この投稿はかなり古いものですが、それでもそれはそのトピックを探しているときにグーグルで最初に現れたものでした。

(基本的に)同じことを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());

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

61
Fat_FS
list1.retainAll(list2) - is intersection

ユニオンはremoveAllになり、次にaddAllになります。

詳細については、コレクションのドキュメントを参照してください(ArrayListはコレクションです) http://download.Oracle.com/javase/1.5.0/docs/api/Java/util/Collection.html

32
The GiG

リストではなくセットに対してのみ定義された共用体と交差点。あなたが言ったように。

guava ライブラリのフィルターを確認してください。また、guavaは実際の 交差点と結合 を提供します

 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)
18
Stan Kurilin

Apache commons からCollectionUtilsを使用できます。

10
bluefoot

マークされたソリューションは効率的ではありません。 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でも同様かどうかはわかりません)。

8
AJed

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

4
ColinD

ストリームとの交差を行う方法を次に示します(ストリームには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());
4
Deutro
  • retainAllはリストを変更します
  • グアバにはリスト用のAPIはありません(セット専用)

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

既存のリストを変更したくない場合は、org.Apache.commons.collectionsのListUtilsを使用します。

ListUtils.intersection(list1, list2)

3
Bala

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

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]
1
xxg

私も同様の状況に取り組んでいて、助けを求めてここにたどり着きました。配列の独自のソリューションを見つけることになりました。 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
Shubham Pandey

リスト内のオブジェクトがハッシュ可能な場合(つまり、適切なhashCodeとequals関数がある場合)、テーブル間の最速のアプローチはsize> 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
Jeroen Vuurens

まず、配列のすべての値を単一の配列にコピーしてから、重複した値を配列に削除しています。行12は、同じ数が時間よりも多く発生する場合、「j」の位置に余分なガベージ値を入れることを説明しています。最後に、start-endからトラバースし、同じガベージ値が発生するかどうかを確認してから破棄します。

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]+" ");
    }
}   
}
0
Ashutosh

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

純粋な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));
}
0
Dilabeing

最終的な解決策:

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

共通キーに基づく異なるオブジェクトの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());
    }
0
Niraj Sonawane