有没有办法根据一个字段对两个不同对象的两个ArrayLists进行内连接?
让我说我得到了:
ArrayList<Car>
ArrayList<Owner>
Car将具有以下属性:Weight, Top speed, OwnerId
所有者将拥有以下属性:Name, Age, Id
结果将是ArrayList<Result>
,其属性为:Weight, Top speed, Id, Name, Age
我想根据名为Id
的单个字段建立这两个字段的内部联接。没有使用数据库或嵌套循环,有没有最佳方法呢?
答案 0 :(得分:2)
假设你:
List<Car> cars
和List<Owner> owners
Result
有一个带有Car
和Owner
这是List<Result>
:
final Map<Integer, Owner> ownersById = owners.stream()
.collect(Collectors.toMap(k -> k.id, k -> k));
final List<Result> results = cars.stream()
.map(car -> new Result(car, ownersById.get(car.OwnerId)))
.collect(Collectors.toList());
其中:
java.util.Map
实例,其中键是所有者ID,值是所有者实例Result
个实例,其中包含对汽车和所有者的引用,使用之前创建的地图查找答案 1 :(得分:1)
您想象它的方式是不可能的,尤其是ArrayList只能包含一种类型(或子类型/实现类)。但是,对于您来说,使用另一个通过其ID来映射对象的数据结构可能是一种解决方案。
HashMap<Integer, HashMap<Car, Owner>> map;
修改强> HashMap中的Integer-type可用于存储id,它是汽车和所有者之间的连接。如果您执行以下操作:
map.get(10)
它将作为HashMap实例返回,包含一个汽车作为键,一个所有者作为相应值,两者都应具有id 10.但这不是隐含的,你必须通过创建Map来确保它。 / p>
此外,您可以编写一个“映射”内连接的类:
public class CarToOwner() {
private Car car;
private Owner owner;
}
修改强> 如果您有一个包含汽车和所有者的类,它会直接映射它们之间的关系。在创建CarToOwner类的实例时,您必须确保两种类型的id与它们之间的连接相同。
事实上,这不是属于某些目的的真正干净的解决方案。我只会将其用作在GUI中显示表格的“快速而肮脏”的方法。
修改强> 对于拥有多个车主或拥有多辆车的车主,有必要将属性存储在CarToOwner的列表中或创建多个CarToOwner实例。
答案 2 :(得分:1)
首先迭代List<Car>
(您应该使用接口而不是实现)并在Map<Integer, Car>
中添加每个元素。 (我认为ID是唯一的。)
然后迭代List<Owner>
并将结果存储在List<Result>
中。当然,你需要一个结构的构造函数来获取一个Car和一个所有者。
此处没有嵌套循环:)
答案 3 :(得分:1)
您可以使用Collection.retainAll()方法。
您必须以特殊方式(请参阅下面的代码)实现等于Car和Owner类中的方法。
例如,假设Car和Owner类都具有String id属性,则代码为:
public static void main(String[] args) {
ArrayList<Car> list1 = new ArrayList<Car>();
list1.add(new Car("ID1"));
list1.add(new Car("ID2"));
list1.add(new Car("ID3"));
ArrayList<Owner> list2 = new ArrayList<Owner>();
list2.add(new Owner("ID1"));
list2.add(new Owner("ID3"));
list2.add(new Owner("ID4"));
list1.retainAll(list2);
System.out.println(list1);
}
static class Car
{
public Car(String id)
{
super();
this.id = id;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (obj instanceof Owner)
{
Owner other = (Owner) obj;
if (id == null)
{
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
}
else if (obj instanceof Car)
{
Car other = (Car) obj;
if (id == null)
{
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
}
return true;
}
@Override
public String toString()
{
return "Car [id=" + id + "]";
}
public String id;
}
static class Owner
{
public Owner(String id)
{
super();
this.id = id;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (obj instanceof Owner)
{
Owner other = (Owner) obj;
if (id == null)
{
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
}
else if (obj instanceof Car)
{
Car other = (Car) obj;
if (id == null)
{
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
}
return true;
}
@Override
public String toString()
{
return "Owner [id=" + id + "]";
}
public String id;
}
输出将是:
[Car [id = ID1],Car [id = ID3]]
显然在这种情况下你会有一个Car列表,如果你想要另一种类型,你可以确保两个类都继承自同一个超类,或者你可以确保两个类实现相同的接口而不是管理那个接口类型。
答案 4 :(得分:1)
假设Id
的类型实现Comparable
:
首先,对列表进行排序,以便Id
按升序排列:
Collections.sort(cars, new Comparator<Car>() {
@Override public int compare(Car a, Car b) {
return a.OwnerId.compareTo(b.OwnerId);
}
});
Collections.sort(owners, new Comparator<Owner>() {
@Override public int compare(Owner a, Owner b) {
return a.Id.compareTo(b.Id);
}
});
然后,遍历元素:
int ci = 0, oi = 0;
while (ci < cars.size() && oi < owners.size()) {
浏览cars
列表,查找Id
字段相同的连续块:
Id idStart = cars.get(ci).OwnerId;
int carStart = ci;
while (ci < cars.size() && cars.get(ci).OwnerId.equals(idStart)) {
++ci;
}
List<Car> carsWithId = cars.subList(carStart, ci);
然后跳过具有较小Owner
s的所有Id
个实例:
while (oi < owners.size() && owners.get(oi).Id.compareTo(idStart) < 0) {
++oi;
}
然后找到与Owner
具有相同Id
的{{1}}个实例的块:
int ownerStart = oi;
while (oi < owners.size() && owners.get(oi).Id.equals(idStart)) {
++oi;
}
List<Owner> ownersWithId = owners.subList(ownerStart, oi);
最后,使用相同的ID对汽车/所有者对执行某些操作:
for (Car car : carsWithId) {
for (Owner owner : ownersWithId) {
System.out.println(car + ", " + owner);
}
}
}
答案 5 :(得分:0)
如果你只想要两个数组的交集,你只需要在一个列表上循环,每当你在另一个列表中找到一个与当前循环元素具有匹配ID的元素时,将它放在第三个列表上(你想要持有交叉元素的那个)