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
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
不知道你说的是不是这个:
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 + ")";
}
}
}
4 回答1.5k 阅读✓ 已解决
4 回答1.3k 阅读✓ 已解决
1 回答2.6k 阅读✓ 已解决
3 回答1.8k 阅读
2 回答769 阅读✓ 已解决
2 回答1.7k 阅读
2 回答1.3k 阅读
如果两个集合的泛型类是同一类,重写equals方法,直接用
set
合并。不是同一类没法合并。