2つのリストがあります。それらには異なるタイプのオブジェクトが含まれていますが、両方のタイプにidと名前が含まれており、idは私が比較しているものです。リスト1はDBから取得され、リスト2はフロントエンドから送信されます。
私がする必要があるのは、それらをループして、どのリスト項目が新しく追加され、どれが削除されたかを見つけることです。
できましたが、問題は見苦しいことです。
Idとnameを持つことができるNameDTOと呼ばれるオブジェクトがあるとしましょう。リスト2は、そのタイプのオブジェクトで満たされています。
これは私がやった方法です:
final ArrayList<NamedDTO> added = new ArrayList<>();
final ArrayList<NamedDTO> removed = new ArrayList<>();
for(NamedDTO listTwoObject : listTwo) {
boolean contained = false;
for(SomeObject listOneObject : listOne) {
if(listTwoObject.getId().equals(listOneObject.getId()) {
contained = true;
}
}
if(!contained) {
added.add(listTwoObject);
}
}
for(SomeObject listOneObject : listOne) {
boolean contained = false;
for(NamedDTO listTwoObject : listTwo) {
if(listTwoObject.getId().equals(listOneObject.getId()) {
contained = true;
}
}
if(!contained) {
removed.add(new NamedDTO(listOneObject.getId(), listOneObject.getName()));
}
}
これは動作します、私はそれをテストしました。より良い解決策はありますか?セットを比較して比較できるように、セットを使用することを考えていましたが、それには欠点がありますか?
私が正しく理解している場合、これはシナリオ例です:
[A, B, C, D]
_[B, C, D, E, F]
_効果として取得する必要があるものは次のとおりです。
[E, F]
_[A]
_まず最初に、タイプアダプターを使用するか、1つの共通クラスとoverride
の異なるタイプをequals
メソッドに拡張して、id
およびname
で一致できるようにします
第二に、これはセットでの非常に簡単な操作です(セットを使用できますが、リストも問題ありません)。ライブラリの使用をお勧めします: https://commons.Apache.org/proper/commons-collections/apidocs/org/Apache/commons/collections4/CollectionUtils.html
そして今、基本的に:
listTwo - listOne
_listOne - listTwo
_およびJavaコードを使用:
CollectionUtils.removeAll(listTwo, listOne)
CollectionUtils.removeAll(listOne, listTwo)
それ以外の場合は、Collection
( Java Docs )を実装するすべてのコレクションにもremoveAll
メソッドがあり、使用できます。
Java 8ストリームを使用してソリューションを提案します。
ArrayList<ObjOne> list = new ArrayList<>(Arrays.asList(new ObjOne("1","1"),new ObjOne("3","3"),new ObjOne("2","2")));
ArrayList<ObjTwo> list2 = new ArrayList<>(Arrays.asList(new ObjTwo("1","1"),new ObjTwo("3","3"),new ObjTwo("4","4")));
List<ObjOne> removed = list.stream().filter(o1 -> list2.stream().noneMatch(o2 -> o2.getId().equals(o1.getId())))
.collect(Collectors.toList());
System.out.print("added ");
removed.forEach(System.out::println);
List<ObjTwo> added = list2.stream().filter(o1 -> list.stream().noneMatch(o2 -> o2.getId().equals(o1.getId())))
.collect(Collectors.toList());
System.out.print("removed ");
added.forEach(System.out::println);
これは基本的にあなたのソリューションですが、ストリームを使用して実装されているため、コードが短くなり読みやすくなります
このネストされたリストの処理は見苦しいだけでなく、非効率的です。 1つのリストのIDをSet
に保存して、効率的なルックアップを可能にしてから、Set
を使用して他のリストを処理することをお勧めします。この方法では、list1.size()
回list2.size()
操作を実行するのではなく、list1.size()
プラスlist2.size()
操作を実行します。リスト。次に、両方の操作は基本的に同じであるため、メソッドに抽象化する価値があります。
public static <A,B,R,ID> List<R> extract(
List<A> l1, List<B> l2, Function<A,ID> aID, Function<B,ID> bID, Function<A,R> r) {
Set<ID> b=l2.stream().map(bID).collect(Collectors.toSet());
return l1.stream().filter(a -> !b.contains(aID.apply(a)))
.map(r).collect(Collectors.toList());
}
このメソッドは次のように使用できます
List<NamedDTO> added = extract(listTwo, listOne, NamedDTO::getId, SomeObject::getId,
Function.identity());
List<NamedDTO> removed = extract(listOne, listTwo, SomeObject::getId, NamedDTO::getId,
so -> new NamedDTO(so.getId(), so.getName()));
2つのリストを交換するには、ヘルパーメソッドが要素タイプから独立している必要があるため、メソッド参照を介して指定できるidプロパティにアクセスするための関数が必要です。次に、結果要素を記述する関数が必要です。これは、ある場合には恒等関数(NamedDTO
を取得する)と、NamedDTO
からSomeObject
を構築するラムダ式ですもう一方。
操作自体は上記のように簡単で、1つのリストを反復処理し、idにマップしてSet
に収集し、次に他のリストを反復処理して、idがセットにない要素のみを保持します。 、結果タイプにマップし、List
に収集します。
これらのIDが一意であれば、それらをHashSetに入れて、興味のあるIDを見つけることができます。
Set<Integer> uiList = Stream.of(new FromUI(1, "db-one"), new FromUI(2, "db-two"), new FromUI(3, "db-three"))
.map(FromUI::getId)
.collect(Collectors.toCollection(HashSet::new));
Set<Integer> dbList = Stream.of(new FromDB(3, "ui-one"), new FromDB(5, "ui-five"))
.map(FromDB::getId)
.collect(Collectors.toCollection(HashSet::new));
uiList.removeIf(dbList::remove);
added/uiSet : [1,2]
removed/dbSet : [5]
入力としてIDと名前を受け取るコンストラクターを使用して、FromUI
クラスとFromDB
クラスを作成しました。
また、要素がuiSet
に含まれているが、dbSet
に含まれていない場合は追加されていると仮定します。