Java中List和Map的特性对两组大批量数据进行匹配

 

在项目中遇到一个问题:要将通过http方式发送过来的大批量数据(这个数据保守估计每次请求在10万条左右),要和数据库中的另一批数据(数据库中的记录1万条左右)进行匹配(匹配:指两组数据中的某几个字段值相等),匹配上的数据保存在数据库中,匹配不上的直接扔掉。或者说:有一个List<String> strList,List<Person> personList,strNoList.size是1万,personList.size是10万, 然后要从personList中把person的id属性在strList中的person取出来,personList中的person的id可能会相同,两个记录的结构不同。

要实现这个功能,首先想到的就是使用for循环逐条进行比较,那么这样就有10W*1W,即10亿次循环。但是,系统对数据的实时性要求比较高,这样做显然性能上是有问题的。于是乎就要找另一种方式,减少循环次数来提高匹配的处理速度,由于之前也没做个这样的事情,于是就想各种办法,同时在OSC社区发帖求助

List可以放重复数据,而Map为不能放重复数据的key-value结构。那么就可以把接收到的id相同的person实体数据放入一个list中,然后用该id作为key,list做作为value放入map中。那么现在处理10w条数据则需要10W次for循环。然后查出数据库中的1W条记录,遍历map,使用map.get("key")取出相同id的list,然后将这些list的元素全部添加到一个resultList中,遍历这1W条记录需要1W次for循环。这样,就将一个10W*1W次的for循环减小到10W+1W次。下边是关于for循环次数的耗时测试,结果表明减少循环次数能大幅度提高处理速度

 代码如下 复制代码

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

/**
 * For循环测试
 * @author 大漠
 *
 */
public class ForTest {
 public static void main(String[] args) {
  ForTest test = new ForTest();
  System.out.println("============开始=============");
   //一亿次for循环
   test.test1Yi();
   //十一万次for循环
   test.test11W();
   //嵌套for循环匹配:10W*1W次for循环
   test.testForAndFor();
   //Map和List整理匹配:10W+1W次for循环
   test.testMapAndList();
  System.out.println("============结束=============");
 }
 /**
  * 一亿次for循环
  */
 private void test1Yi(){
  long start = System.currentTimeMillis();
  for (Integer i = 0; i < 100000000;i++) {
   System.out.println(i);
  }
  long end = System.currentTimeMillis();
  System.out.println("1亿次循环耗时:"+ (end - start) + "毫秒");
  System.out.println("----------------------------");
 }
 
 /**
  * 11万次for循环
  */
 private void test11W(){
  long start = System.currentTimeMillis();
  for (Integer i = 0; i < 110000;i++) {
   System.out.println(i);
  }
  long end = System.currentTimeMillis();
  System.out.println("11W次循环耗时:"+ (end - start) + "毫秒");
  System.out.println("----------------------------");
 }
 
 /**
  * 嵌套for循环进行比较匹配
  */
 private void  testForAndFor(){
  //构造一个10万个Person对象的list
  List<Person> personList = new ArrayList<Person>();
  for (int i = 0; i < 100000; i++) {
   int j =10000;
   personList.add(new Person((i%j) +"", "张三"+i));
  }
  //构造一个1万个String对象的list
  List<String> strList = new ArrayList<String>();
  for (int i = 0; i < 10000; i++) {
   strList.add(i +"");
  }
  
  //嵌套for循环:10W*1W
  long start = System.currentTimeMillis();
  //保存匹配结果
        List<Person> resultList = new ArrayList<Person>();
        //遍历10W person的List
        for (Person person : personList) {
         //遍历1W str的List
            for (String str : strList) {
                if(person.getId().equals(str)){
                    resultList.add(person);
                }
            }
        }
        long end = System.currentTimeMillis(); 
        System.out.println("reslutList.size:"+ resultList.size());
        System.out.println("10W*1W次循环耗时:"+ (end - start) + "毫秒");
        System.out.println("----------------------------");
 }
 
 /**
  * 使用Map和List的特性进行匹配:
  * Map为key-value结构,不能放重复数据
  * List可以放重复数据
  * 使用String型id做key,List<Person>做value
  * 遍历List<String>, map.get(String)则取出id == str 的List
  */
 private void  testMapAndList(){
  //构造一个10万个Person对象的list
  List<Person> personList = new ArrayList<Person>();
  
  for (int i = 0; i < 100000; i++) {
   int j =10000;
   personList.add(new Person((i%j) +"", "张三"+i));
  }
  //构造一个1万个String对象的list
  List<String> strList = new ArrayList<String>();
  for (int i = 0; i < 10000; i++) {
   strList.add(i +"");
  }
  
  long start = System.currentTimeMillis();
  //利用Map和List的特性整理数据
        Map<String, List<Person>> map = new HashMap<String, List<Person>>();
        //将10W条数据根据id放入map
        for(int i=0;i<personList.size();i++){
         Person person = personList.get(i);
             String id = person.getId();
              if(map.containsKey(id)){
                  map.get(id).add(person);
              }else{
                   List<Person> pList = new ArrayList<Person>();
                   pList.add(person);
                   //id为key,相同id的person的List为value
                   map.put(id,pList);
             }
        }
      //保存匹配结果
        List<Person> resultList = new ArrayList<Person>();
        //根据1W条str,map.get(str)取匹配上的数据
        for (String str : strList) {
            List<Person> pList = map.get(str);
            if (pList != null) {
                resultList.addAll(pList);
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("map.size:" +map.size());
        System.out.println("reslutList.size:"+ resultList.size());
        System.out.println("10W+1W次循环耗时:"+ (end - start) + "毫秒");
  System.out.println("----------------------------");
 }

}

/**
 * Person实体类
 */
class Person{
 private String id;
 private String name;

 public Person() {}
 
 public Person(String id, String name) {
  this.id = id;
  this.name = name;
 }

 @Override
 public String toString() {
  return this.id +"::>"+ this.name;
 }
 
 public String getId() {
  return id;
 }
 public void setId(String id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
}

测试结果:

============开始=============
1亿次循环耗时:1262985毫秒
----------------------------
11W次循环耗时:1016毫秒
----------------------------
reslutList.size:100000
10W*1W次循环耗时:21219毫秒
----------------------------
map.size:10000
reslutList.size:100000
10W+1W次循环耗时:31毫秒
============结束=============

•1亿次system.out.println(i)的循环耗时1262985毫秒,即21分钟,那么10亿次210分钟,显然不可接受。当然这里设计I/O操作,比较耗时,实际应用中没有这么吓人。
•11万次system.out.println(i)循环耗时1016毫秒,即1秒种,很明显,减少循环次数能够提高处理速度。
•使用嵌套for循环完成10W*1W次循环耗时21219毫秒,使用第二种方法完成10W+1W次循环耗时31毫秒,处理速度提高了600多陪,达到了预想的目的。

时间: 2024-10-23 19:31:14

Java中List和Map的特性对两组大批量数据进行匹配的相关文章

java 文件输入输...-关于JAVA中文件的map写入操作

问题描述 关于JAVA中文件的map写入操作 想实现一个功能,首先有个map,不过只有一条数据.判断在指定路径是否有文件存在,如果没有则先创建再将map写入,如果指定路径有文件存在则直接写入或者,追加记录.谢谢了 解决方案 File.isFile方法可以判断文件是否存在: 写入的追加可以在申明输出流的时候加标志: 例如new FileOutputStream(File or filename, append) append为true表示追加写入: 如果要直接写入map,可以用序列化. 解决方案二

java中接口没有构造方法那子类怎么访问他的数据

问题描述 java中接口没有构造方法那子类怎么访问他的数据 感觉跟以往学过的知识冲突了?哪位大神能伸出援手解答下?这个问题困扰我好久了,希望走过路过的不要错过哈! 解决方案 接口有什么数据?接口就是一个定义,不存任何数据. 解决方案二: 接口中没有任何函数,接口不是类,不能构造一个接口.只能构造一个实现了这个接口的函数. 解决方案三: 接口就是公共方法的集合,只有公有常量和抽象方法,数据是类的属性,只有类才可以定义私有成员变量的. 解决方案四: 接口,不能实例化,没有构造方法 解决方案五: 接口

java中的结束日期为什么获取不到等于的数据

问题描述 java中的结束日期为什么获取不到等于的数据 这样写就越界了 应该怎么写 解决方案 看看endDate是什么值,endDate字符串没有那么长,越界了. 解决方案二: endDate总共都没有10个长度,你截取10个长度,当然报错了 解决方案三: 有两个可能 1.你的endDate没有10个长度 2.我看你的回复enddate的值为null,但是你在if条件中做了trim操作,null是不可以trim的吧...而且值为null的话应该不会执行if的第二个条件了吧.. 你打断点看看 解决

java组件-java中布局LinearLayout和组件ListView属于什么类型的数据?

问题描述 java中布局LinearLayout和组件ListView属于什么类型的数据? 因为我看到都可以定义为变量,所以他们肯定属于某种数据类型,肯定不是基本数据类型,那是引用数据类型吗,如果是引用数据类型,那取值范围是什么 解决方案 1.java中的数据类型分为基本类型与引用类型. 2.LinearLayout和ListView都是类,它们的实例是引用类型. 3.对于LinearLayout和ListView这样的类,你可以实例化无数个对象,所以它们没有取值范围. 4.有一些特殊的类:单例

JAVA中对存储过程的调用方法(六) 增加数据的存储过程

六.增加数据的存储过程 ------------存储过程-------------------- create procedure InsertPro @StuID int, @StuName varchar(10), @StuAddress varchar(20) as insert into 学生基本信息表 values(@StuID,@StuName,@StuAddress) -----------调用存储过程--------------- exec InsertPro 5,'555','

JAVA中对存储过程的调用方法(五) 查询数据的存储过程(模糊查询)

五.查询数据的存储过程(模糊查询) -----------------存储过程--------------------- create procedure FindCusts @cust varchar(10) as select customerid from orders where customerid like '%'+@cust+'%' ---------------执行--------------------------- execute FindCusts 'alfki' ----

JAVA中对存储过程的调用方法(三) 删除数据的存储过程

三.删除数据的存储过程 ------------------存储过程-------------------------- drop table 学生基本信息表 create table 学生基本信息表 ( StuID int primary key, StuName varchar(10), StuAddress varchar(20) ) insert into 学生基本信息表 values(1,'三毛','wuhan') insert into 学生基本信息表 values(2,'三毛','

Java中如何遍历Map对象

博主有时会忘记如何遍历Map对象,这次在这里做一下总结.博主采用的是JDK7,先看一下JDK7中Map接口的定义. java.util Interface Map<K,V> 类型参数: K - the type of keys maintained by this map V - the type of mapped values All Known Subinterfaces: Bindings,ConcurrentMap<K,V>, ConcurrentNavigableMap

java中数组list map三者之间的互转介绍_java

三者之间转换关系,一张图清晰呈现.  上代码: 其中的maputils是apache的collection包. 复制代码 代码如下: package util; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.collections.MapUtil