Java2个对象形集合按某一个属性合并

List<objA> list_a = new ArrayList<objA>();
List<objB> list_b = new ArrayList<objB>();

其中objA.empNo = objB.empNo

请问如何合并这2个集合效率高?

补充:结果大概类似sql的

list_b left join list_a on objA.empNo = objB.empNo
阅读 10.7k
8 个回答

如果两个集合的泛型类是同一类,重写equals方法,直接用set合并。不是同一类没法合并。

不知道你说的是不是这个:

package com.segmentfault.qa.java;

import java.util.*;

public class ListMergeTest {

    public static void main(String[] args) {
        List<ClsA> listA = new ArrayList<>();
        List<ClsB> listB = new ArrayList<>();
        Map<String, Map<String, Object>> resultMap = new HashMap<>();
        
        listA.add(new ClsA("001", "Alex"));
        listA.add(new ClsA("002", "Bill"));
        listA.add(new ClsA("003", "Carl"));
        
        listB.add(new ClsB("001", 1000));
        listB.add(new ClsB("002", 2000));
        listB.add(new ClsB("004", 4000));
        
        for(ClsA a: listA){
            Map<String, Object> map = new HashMap<>();
            String empNo = a.getEmpNo();
            for(ClsB b: listB){
                if(b.getEmpNo().equals(empNo)){
                    map.put("money", b.getMoney());
                }
            }
            map.put("name", a.getName());
            resultMap.put(empNo, map);
        }
        
        System.out.println(resultMap);
    }
}

class ClsA{
    private String empNo;
    private String name;
    
    public ClsA(String empNo, String name){
        this.empNo = empNo;
        this.name = name;
    }
    
    public String getEmpNo() {
        return empNo;
    }
    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

class ClsB{
    private String empNo;
    private int money;
    
    public ClsB(String empNo, int money){
        this.empNo = empNo;
        this.money = money;
    }
    
    public String getEmpNo() {
        return empNo;
    }
    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }
    public int getMoney() {
        return money;
    }
    public void setMoney(int money) {
        this.money = money;
    }
}

感觉循环肯定是少不了,但是感觉怎么减少循环才是优化方向吧,减少一个循环数据量越大效率越明显。

package demo_java;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test1 {
    public static void main(String[] args) {
        List<ObjA> listA = new ArrayList<>();
        List<ObjB> listB = new ArrayList<>();
        // 构建10W数据
        for(int i=0; i<100000; ++i) {
            ObjA a = new ObjA("no"+i, "name"+i);
            listA.add(a);
        }
        for(int i=8888; i<106666; ++i) {
            ObjB b = new ObjB("no"+i, "infos"+i);
            listB.add(b);
        }
        int aSize = listA.size();
        int bSize = listB.size();
        // listA Size: 100000
        System.out.println("listA Size: " + aSize);
        // listB Size: 97778
        System.out.println("listB Size: " + bSize);
        Long sTime = System.currentTimeMillis();
        Map<String, ObjC> map = new HashMap<>();
        // 减少一个循环,取最大的循环数
        int maxSize = aSize > bSize ? aSize : bSize;
        for(int i=0; i<maxSize; ++i) {
            ObjA a = null;
            ObjB b = null;
            // 如果小于listA的个数
            if(i < listA.size()) {
                a = listA.get(i);
            }
            // 如果小于listB的个数
            if(i < listB.size()) {
                b = listB.get(i);
            }
            if(a != null) {
                ObjC c = map.get(a.getEmpNo());
                if( c == null ) {
                    c = new ObjC();
                    map.put(a.getEmpNo(), c);
                } 
                c.setA(a);
            }
            if(b != null) {
                ObjC c = map.get(b.getEmpNo());
                if( c == null ) {
                    c = new ObjC();
                    map.put(b.getEmpNo(), c);
                } 
                c.setB(b);
            }
        }
        Long eTime = System.currentTimeMillis();
        System.out.println((eTime - sTime)+"ms");
        // empNo:no888, name:no888, infos:
        System.out.println(map.get("no888"));
        // empNo:no8888, name:no8888, infos:infos8888
        System.out.println(map.get("no8888"));
        // empNo:no106665, name:, infos:infos106665
        System.out.println(map.get("no106665"));
        // 106666
        System.out.println(map.values().size());
    }
}
class ObjC {
    private ObjA a;
    private ObjB b;
    
    public ObjA getA() {
        return a;
    }
    public void setA(ObjA a) {
        this.a = a;
    }
    public ObjB getB() {
        return b;
    }
    public void setB(ObjB b) {
        this.b = b;
    }
    @Override
    public String toString() {
        String empNo = a == null ? b.getEmpNo() : a.getEmpNo();
        String name = a == null ? "" : a.getEmpNo();
        String infos = b == null ? "" : b.getInfos();
        return "empNo:"+empNo+", name:"+name+", infos:"+infos;
    }
}

class ObjA{
    private String empNo;
    private String name;
    
    public ObjA(String empNo, String name){
        this.empNo = empNo;
        this.name = name;
    }
    public String getEmpNo() {
        return empNo;
    }
    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

class ObjB{
    private String empNo;
    private String infos;
    
    public ObjB(String empNo, String infos){
        this.empNo = empNo;
        this.infos = infos;
    }
    public String getEmpNo() {
        return empNo;
    }
    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }
    public String getInfos() {
        return infos;
    }
    public void setInfos(String infos) {
        this.infos = infos;
    }
}

@机智的熊大@martinwangjun 的解答思路应该是符合你的需求的,我根据他的代码修改了另外一套解决方案,使用纯list的方式,具体代码如下:

import java.util.ArrayList;
import java.util.List;

public class ListMergeTest_1 {

    public static void main(String[] args) {
        List<ClassA> listA = new ArrayList<>();
        List<ClassB> listB = new ArrayList<>();
        List<ClassC> listC = new ArrayList<>();
        
        listA.add(new ClassA("001", "Alex"));
        listA.add(new ClassA("002", "Bill"));
        listA.add(new ClassA("003", "Carl"));
        
        listB.add(new ClassB("001", 1000));
        listB.add(new ClassB("002", 2000));
        listB.add(new ClassB("004", 4000));
        
        for(ClassA a: listA){
            String empNo = a.getEmpNo();
            ClassC c = new ClassC();
            c.setEmpNo(a.getEmpNo());
            c.setName(a.getName());
            for(ClassB b: listB){
                if(b.getEmpNo().equals(empNo)){
                   c.setMoney(b.getMoney());
                }
            }
            listC.add(c);
        }
        
        System.out.println(listC);
    }
}

class ClassA{
    private String empNo;
    private String name;
    
    public ClassA(String empNo, String name){
        this.empNo = empNo;
        this.name = name;
    }
    
    public String getEmpNo() {
        return empNo;
    }
    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

class ClassB{
    private String empNo;
    private int money;
    
    public ClassB(String empNo, int money){
        this.empNo = empNo;
        this.money = money;
    }
    
    public String getEmpNo() {
        return empNo;
    }
    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }
    public int getMoney() {
        return money;
    }
    public void setMoney(int money) {
        this.money = money;
    }
    
}

class ClassC{
    private String empNo;
    private String name;
    private int money;
    
//    public ClassC(String empNo, String name, int money){
//        this.empNo = empNo;
//        this.name = name;
//        this.money = money;
//    }
    
    public String getEmpNo() {
        return empNo;
    }
    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "(" + empNo + ", " + name + ", " + money + ")";
    }
}
新手上路,请多包涵

恕我愚钝,没看明白题目。。。。

假定objA#empNo是String

Map<String, Object> map = new HashMap<String, Object>();
for (objA a: list_a) {
  map.put(a.empNo, a);
}
for (objB b: list_b) {
  map.put(b.empNo, b);
}
return map.values();

我提供个思路,你把listB改成Map对象,key用empNo,而且你要做合并模拟left join肯定还需要第三个对象C存A B合并后的数据,这样你遍历listA时用a.empNo去mapB取,取到了就合并,并加到listC里,没取到继续遍历,最后如果你有需要用list的地方可以用Map.values()生成

这是属于用空间换时间的办法,免得你每次遍历listA时还要遍历一遍listB,但是内存占用会非常大,因为多存了个keySet

新手上路,请多包涵

用100W条数据简单测了下,合并耗时是分组加上合并

分组完毕:78
合并结束(包含分组时间):158
public static class Test{
    public static void main(String[] args) {
        List<ClassA> listA = new ArrayList<>();
        List<ClassB> listB = new ArrayList<>();
        List<ClassC> listC = new ArrayList<>();
        Integer num = 100_0000;
        for (Integer i = 0; i < num; i++) {
            listA.add(new ClassA("00" + RandomUtil.randomInt(1,10), RandomUtil.randomString(5)));
        }

        listB.add(new ClassB("001", 1000));
        listB.add(new ClassB("002", 2000));
        listB.add(new ClassB("003", 3000));
        listB.add(new ClassB("004", 4000));
        listB.add(new ClassB("005", 5000));
        listB.add(new ClassB("006", 6000));
        listB.add(new ClassB("007", 7000));
        listB.add(new ClassB("008", 8000));
        listB.add(new ClassB("009", 9000));

        long start = System.currentTimeMillis();
        Map<String, List<ClassB>> bMap = listB.parallelStream().collect(Collectors.groupingBy(ClassB::getEmpNo));
        System.out.println("分组完毕:"+ (System.currentTimeMillis() - start));
        listB = null;
        listA.forEach(item -> {
            String empNo = item.getEmpNo();
            List<ClassB> bs = bMap.get(empNo);
            ClassB classB = bs == null ? new ClassB(null, 0) : bs.get(0);
            ClassC c = new ClassC();
            c.setEmpNo(empNo);
            c.setName(item.getName());
            c.setMoney(classB.getMoney());
            listC.add(c);
        });
        System.out.println("合并结束:"+ (System.currentTimeMillis() - start));

        listC.parallelStream().forEach(item -> {
            int n = Integer.parseInt(item.getEmpNo());
            if (item.getMoney() != n * 1000){
                System.err.println("合并错误:" + item);
            }
        });
    }

    static class ClassA{
        private String empNo;
        private String name;

        public ClassA(String empNo, String name){
            this.empNo = empNo;
            this.name = name;
        }

        public String getEmpNo() {
            return empNo;
        }
        public void setEmpNo(String empNo) {
            this.empNo = empNo;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }

    static class ClassB{
        private String empNo;
        private int money;

        public ClassB(String empNo, int money){
            this.empNo = empNo;
            this.money = money;
        }

        public String getEmpNo() {
            return empNo;
        }
        public void setEmpNo(String empNo) {
            this.empNo = empNo;
        }
        public int getMoney() {
            return money;
        }
        public void setMoney(int money) {
            this.money = money;
        }

    }

    static class ClassC{
        private String empNo;
        private String name;
        private int money;

        public String getEmpNo() {
            return empNo;
        }
        public void setEmpNo(String empNo) {
            this.empNo = empNo;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }

        public int getMoney() {
            return money;
        }

        public void setMoney(int money) {
            this.money = money;
        }

        @Override
        public String toString() {
            return "(" + empNo + ", " + name + ", " + money + ")";
        }
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题