我有2个列表,其中包含一些对象(水果类)。我正在使用第三个列表根据以下两个条件添加这些元素。
我希望将第一列表中的每个对象添加到第三列表中。但是,如果我在第二个列表中有一个匹配的对象(基于id和isChecked进行匹配),我想将第二个列表中的对象添加到第三个列表中,而忽略第一个列表中的对象。
如果我做了第一个要点上提到的开关,我想将该对象移到第三个列表的第一个元素上。
我可以使用以下代码。但是我发现它效率很低。有更好的解决方法吗?
请记住,我无法控制第二个列表,但是第一个列表来自Rest端点,我目前正在将其捕获为列表。不确定我是否应该选择地图。请指教。
示例:
在以下示例中,预期列表输出为[f2,f5,f1,f3,f4](基于名称)。
是cos,我拥有第一个列表中的所有元素。 f2和f5来自第二个列表(它们与第一个列表中的元素匹配,并且isChecked设置为true)处于顺序的前面。
import lombok.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App {
public static void main(String[] args) {
Fruit fruit1 = new Fruit("1", "f1", false);
Fruit fruit2 = new Fruit("2", "f2", false);
Fruit fruit3 = new Fruit("3", "f3", false);
Fruit fruit4 = new Fruit("4", "f4", false);
Fruit fruit5 = new Fruit("5", "f5", false);
List<Fruit> firstList = Arrays.asList(fruit1, fruit2, fruit3, fruit4, fruit5);
Fruit fruit6 = new Fruit("2", "f2", true);
Fruit fruit7 = new Fruit("7", "f7", false);
Fruit fruit8 = new Fruit("5", "f5", true);
Fruit fruit9 = new Fruit("9", "f9", false);
Fruit fruit10 = new Fruit("10", "f10", false);
List<Fruit> secondList = Arrays.asList(fruit6, fruit7, fruit8, fruit9, fruit10);
List<Fruit> finalList = new ArrayList<>();
// expected list = [f2, f5, f1, f3, f4]
// this loop is checking and adding objects to finalList.
// must match the first list and isChecked.
// in this case, only f6 and f8 matches the first list (id match) and is also 'checked'.
for (Fruit first : firstList){
for (Fruit second : secondList){
if(first.getId().equals(second.getId()) && second.isChecked()){
finalList.add(second);
break;
}
}
}
// not done yet. Still need to loop and add back the elements from the first list
// which were not added in the above loop
boolean addedFirst = false;
outer:
for(Fruit first : firstList){
for(Fruit finalFruit : finalList){
if(first.getId().equals(finalFruit.getId())){
continue outer;
}
}
finalList.add(first);
}
for(Fruit fruit : finalList){
System.out.println(fruit);
}
}
}
@Getter
@Setter
@ToString
class Fruit{
private String id;
private String name;
private boolean isChecked;
Fruit(String id, String name, boolean isChecked) {
this.id = id;
this.name = name;
this.isChecked = isChecked;
}
}
答案 0 :(得分:3)
我的建议是为Object#equals(java.lang.Object)
类覆盖Fruit
。
$ ls -l /Users/username/workspace/Swift/sis/sis/data.json
-rwxrwxrwx@ 1 username staff 165563 16 Jan 17:14 /Users/username/workspace/Swift/sis/sis/data.json
。 。 。
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Fruit))
return false;
return id.equals(((Fruit)obj).getId());
}
为了保持所需的排序顺序-首先是第二个列表元素,然后是第二个中不匹配的元素-一个可以做到:
for (Fruit fruit : firstList) {
if (secondList.contains(fruit)) {
int index = secondList.indexOf(fruit);
fruit = secondList.get(index);
}
finalList.add(fruit);
}
List<Fruit> finalList = new ArrayList<>(secondList);
finalList.retainAll(firstList);
for (Fruit fruit : firstList) {
if (!finalList.contains(fruit))
finalList.add(fruit);
}
的订单现在为finalList
。
由于[f2, f5, f1, f3, f4]
方法的重写,此方法再次起作用。
请参见java.util.List.retainAll()
。
这些方法中的每一个都为每个循环和搜索操作使用线性 O(n)计算时间-例如equals
和indexOf
。
与该主题相关,我认为您还不清楚要实现什么:
retainAll
和f2
排在第二个列表的前面(它们与第一个列表中的元素匹配,并且f5
设置为isChecked
)在顺序的前面>
如果第一个列表中的true
设置为isChecked
,该怎么办?第二个列表中的元素是否始终排在最前面,并且false
的顺序得以保留,所以基本上您希望在同一结果列表中进行两种不同的排序?
答案 1 :(得分:2)
我认为您可以使用Map
来建立结果列表。构建第三张列表需要 O(n)额外的空间和 O(n)时间。
public static List<Fruit> buildFinalList(List<Fruit> firstList, List<Fruit> secondList) {
Map<String, Fruit> map = secondList.stream().collect(Collectors.toMap(Fruit::getId, Function.identity()));
List<Fruit> finalList = firstList.stream()
.filter(fruit -> map.containsKey(fruit.getId()))
.map(fruit -> map.get(fruit.getId()))
.collect(Collectors.toList());
firstList.stream()
.filter(fruit -> !map.containsKey(fruit.getId()))
.forEach(finalList::add);
return finalList;
}
输出:
Fruit{id='2', name='f2', isChecked=true}
Fruit{id='5', name='f5', isChecked=true}
Fruit{id='1', name='f1', isChecked=false}
Fruit{id='3', name='f3', isChecked=false}
Fruit{id='4', name='f4', isChecked=false}
答案 2 :(得分:0)
您可以在下面尝试
请参见下面的代码,
finalList.addAll(firstList);
for (Fruit secondfruit : secondList) {
boolean isRemoved = finalList.removeIf(firstfruit -> firstfruit.compareTo(secondfruit) == 0);
if(isRemoved) {
finalList.add(secondfruit);
}
}
for (Fruit fruit : finalList) {
System.out.println(fruit.getName());
}
具有可比性的水果类
class Fruit implements Comparable<Fruit> {
private String id;
private String name;
private boolean isChecked;
@Override
public int compareTo(Fruit o) {
if (o.isChecked && this.id.equalsIgnoreCase(o.id)) {
return 0;
}
else {
return 1;
}
}
}
结果是, f1 f3 f4 f2 f5
答案 3 :(得分:0)
假设firstList的长度为n,secondList的长度为m,则您可能需要花费O(nlogn) + O(mlogm) +O(n+m)
来解决问题。像合并排序这样的算法。
public static List<Fruit> merge(List<Fruit> list1, List<Fruit> list2) {
// sort list1 and list2
Comparator<Fruit> comparator = Comparator.comparingInt(o -> Integer.parseInt(o.getId()));
Collections.sort(list1, comparator);
Collections.sort(list2, comparator);
List<Fruit> finalList1 = new ArrayList<>();
List<Fruit> finalList2 = new ArrayList<>();
int length1 = list1.size();
int length2 = list2.size();
int index1 = 0;
int index2 = 0;
while (index1 < length1 && index2 < length2) {
Fruit fruit1 = list1.get(index1);
Fruit fruit2 = list2.get(index2);
if (fruit1.getId().equals(fruit2.getId()) && fruit2.isChecked()) {
finalList2.add(fruit2);
index2++;
index1++;
} else {
finalList1.add(fruit1);
index1++;
}
}
while (index1 < length1) {
finalList1.add(list1.get(index1));
index1++;
}
finalList2.addAll(finalList1);
return finalList2;
}