"左连接"两个不同的Java对象

时间:2014-08-31 15:57:33

标签: java left-join

我有一个Object1(List<Object1>)列表和一个Object2列表(List<Object2>

  • 对象1有多个属性,包括id
  • 对象2有多个属性,包括object1id

我有一些SQL背景,我尝试做的是执行&#34;左连接&#34;上

object1.id = object2.object1id

这将导致代表左连接的List<Object3>。 我可以用Java硬编码算法(for ... for ...),但我确信这对于至少n * m的复杂度来说不会有效。

你有更好的解决方案吗? (如果可能,请附上代码,谢谢!)

6 个答案:

答案 0 :(得分:7)

你正在尝试做一些Java并不是真正意义上的事情。

如果你能够做到这一点,你最好将属性添加到Object1 ,这将是包含与{相关的对象的Object2的列表。 {1}}。

如果你不能,我们仍然可以选择天真地做,否则你可以尝试这样的事情:

this

不完美,因为你必须将所有id存储在HashSet中,但由于在HashSet中添加和访问元素是O(1)(理论上),算法是O(n + m)

如果您的HashSet<Integer> hs = new HashSet<Integer>(list2.size()); for(Object2 o : list2) { hs.add(o.object1id); } //hs contains all the ids of list2 List<Object1> result = new ArrayList<Object1>(); //Or another class implementing List for(Object1 o : list1) { if(hs.contains(o.id)) result.add(o); } 课程是使用Object3Object1构建的,请使用Object2代替HasMap,其中键为ID,值为对象2。代码中的最后一个HashSet循环将变为:

for

进一步对ÓscarLópez发表评论:

如果你的目标是不唯一的,你必须按如下方式调整代码:

Object2 o2 = hs.get(o.id);
if(o2 != null)
    result.add(new Object3(o, o2);

仍然在O(n + m),但有更大的常数...

答案 1 :(得分:2)

在List上创建索引。扫描列表并填写索引:

HashMap<Integer, Object2> index=HashMap<Integer, Object2>();
for (Object2 obj2: list2) {
   index.put(obj2.object1id, obj2);
}

然后,扫描列表并进行连接:

for (Object1 obj1: list1) {
   Object2 obj2=index.get(obj1.id); // may be null
   Object3 obj3=new Object3(obj1, obj2);
}

答案 2 :(得分:1)

如果您使用的是Java 8,则可以使用streams。它可能看起来像这样(假设id是要查找的Object1的id):

List<Object3> newList = obj2List.stream().filter(x -> x.object1id == id).map(x -> obj2To3(x)).collect(Collectors.toList());

提供的案例非常模糊,因此很难给出更详细的答案。

答案 3 :(得分:1)

我认为O(n*m)解决方案是不可避免的,除非创建更复杂的数据结构基础结构 - 数据库中的高效连接是implemented使用索引,哈希等。另外请记住,正确的实现应考虑list2中的多个对象具有相同object1id的情况 - 我的代码在这种情况下有效,但所有解决方案只添加{{1} } obj2.object1idSet中的键会失败。

但实施复杂性值得吗?如果输入列表很小,Map解决方案就可以正常工作。这是我的建议,使用好的旧嵌套循环:

O(n*m)

为了实现上述目的,我使用的输出对象如下所示:

List<Object3> list3 = new ArrayList<>();
for (Object1 obj1 : list1) {
    boolean found = false;
    for (Object2 obj2 : list2) {
        if (obj1.id.equals(obj2.object1id)) {
            list3.add(new Object3(obj1, obj2));
            found = true;
        }
    }
    if (!found)
        list3.add(new Object3(obj1, null));
}

答案 4 :(得分:1)

一个好的解决方案可能是将Object2的List转换为Map。然后遍历Object1 List并从Map获取Object2,最终创建Join并在Object3 List中添加结果。

答案 5 :(得分:0)

如果它们实现了一些通用接口(这会使事情变得更容易,特别是使用转换),那么这是相对简单的。

它仍然是O(nm),因为您必须遍历列表的两个长度才能找到要添加的元素。

public interface JoinInterface {
    int getId();
    int getObject1Id(); // likely baggage here
}


public static List<? extends JoinableEntity> leftJoin(List<? extends JoinableEntity> left,
                                               List<? extends JoinableEntity> right) {
    List<JoinableEntity> result = new ArrayList<>();

    result.addAll(left);
    for(JoinableEntity aLeft : left) {
        for(JoinableEntity aRight : right) {
            if(aLeft.getId() == aRight.getObject1Id()) {
                result.add(aRight);
                break;
            }
        }
    }

    return result;
}