zoukankan      html  css  js  c++  java
  • 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循环次数的耗时测试,结果表明减少循环次数能大幅度提高处理速度

      1 import java.util.ArrayList;
      2 import java.util.HashMap;
      3 import java.util.List;
      4 import java.util.Map;
      5 /**
      6  * For循环测试
      7  * @author 大漠
      8  *
      9  */
     10 public class ForTest {
     11  public static void main(String[] args) {
     12   ForTest test = new ForTest();
     13   System.out.println("============开始=============");
     14    //一亿次for循环
     15    test.test1Yi();
     16    //十一万次for循环
     17    test.test11W();
     18    //嵌套for循环匹配:10W*1W次for循环
     19    test.testForAndFor();
     20    //Map和List整理匹配:10W+1W次for循环
     21    test.testMapAndList();
     22   System.out.println("============结束=============");
     23  }
     24  /**
     25   * 一亿次for循环
     26   */
     27  private void test1Yi(){
     28   long start = System.currentTimeMillis();
     29   for (Integer i = 0; i < 100000000;i++) {
     30    System.out.println(i);
     31   }
     32   long end = System.currentTimeMillis();
     33   System.out.println("1亿次循环耗时:"+ (end - start) + "毫秒");
     34   System.out.println("----------------------------");
     35  }
     36  
     37  /**
     38   * 11万次for循环
     39   */
     40  private void test11W(){
     41   long start = System.currentTimeMillis();
     42   for (Integer i = 0; i < 110000;i++) {
     43    System.out.println(i);
     44   }
     45   long end = System.currentTimeMillis();
     46   System.out.println("11W次循环耗时:"+ (end - start) + "毫秒");
     47   System.out.println("----------------------------");
     48  }
     49  
     50  /**
     51   * 嵌套for循环进行比较匹配
     52   */
     53  private void  testForAndFor(){
     54   //构造一个10万个Person对象的list
     55   List<Person> personList = new ArrayList<Person>();
     56   for (int i = 0; i < 100000; i++) {
     57    int j =10000;
     58    personList.add(new Person((i%j) +"", "张三"+i));
     59   }
     60   //构造一个1万个String对象的list
     61   List<String> strList = new ArrayList<String>();
     62   for (int i = 0; i < 10000; i++) {
     63    strList.add(i +"");
     64   }
     65   
     66   //嵌套for循环:10W*1W
     67   long start = System.currentTimeMillis();
     68   //保存匹配结果
     69         List<Person> resultList = new ArrayList<Person>();
     70         //遍历10W person的List
     71         for (Person person : personList) {
     72          //遍历1W str的List
     73             for (String str : strList) {
     74                 if(person.getId().equals(str)){
     75                     resultList.add(person);
     76                 }
     77             }
     78         }
     79         long end = System.currentTimeMillis();  
     80         System.out.println("reslutList.size:"+ resultList.size());
     81         System.out.println("10W*1W次循环耗时:"+ (end - start) + "毫秒");
     82         System.out.println("----------------------------");
     83  }
     84  
     85  /**
     86   * 使用Map和List的特性进行匹配:
     87   * Map为key-value结构,不能放重复数据
     88   * List可以放重复数据
     89   * 使用String型id做key,List<Person>做value
     90   * 遍历List<String>, map.get(String)则取出id == str 的List
     91   */
     92  private void  testMapAndList(){
     93   //构造一个10万个Person对象的list
     94   List<Person> personList = new ArrayList<Person>();
     95   
     96   for (int i = 0; i < 100000; i++) {
     97    int j =10000;
     98    personList.add(new Person((i%j) +"", "张三"+i));
     99   }
    100   //构造一个1万个String对象的list
    101   List<String> strList = new ArrayList<String>();
    102   for (int i = 0; i < 10000; i++) {
    103    strList.add(i +"");
    104   }
    105   
    106   long start = System.currentTimeMillis();
    107   //利用Map和List的特性整理数据
    108         Map<String, List<Person>> map = new HashMap<String, List<Person>>();
    109         //将10W条数据根据id放入map
    110         for(int i=0;i<personList.size();i++){
    111          Person person = personList.get(i);
    112              String id = person.getId();
    113               if(map.containsKey(id)){
    114                   map.get(id).add(person);
    115               }else{
    116                    List<Person> pList = new ArrayList<Person>();
    117                    pList.add(person);
    118                    //id为key,相同id的person的List为value
    119                    map.put(id,pList);
    120              }
    121         }
    122       //保存匹配结果
    123         List<Person> resultList = new ArrayList<Person>();
    124         //根据1W条str,map.get(str)取匹配上的数据
    125         for (String str : strList) {
    126             List<Person> pList = map.get(str);
    127             if (pList != null) {
    128                 resultList.addAll(pList);
    129             }
    130         }
    131         long end = System.currentTimeMillis();
    132         System.out.println("map.size:" +map.size());
    133         System.out.println("reslutList.size:"+ resultList.size());
    134         System.out.println("10W+1W次循环耗时:"+ (end - start) + "毫秒");
    135   System.out.println("----------------------------");
    136  }
    137 }
    138 /**
    139  * Person实体类
    140  */
    141 class Person{
    142  private String id;
    143  private String name;
    144  public Person() {}
    145  
    146  public Person(String id, String name) {
    147   this.id = id;
    148   this.name = name;
    149  }
    150  @Override
    151  public String toString() {
    152   return this.id +"::>"+ this.name;
    153  }
    154  
    155  public String getId() {
    156   return id;
    157  }
    158  public void setId(String id) {
    159   this.id = id;
    160  }
    161  public String getName() {
    162   return name;
    163  }
    164  public void setName(String name) {
    165   this.name = name;
    166  }
    167 }

    测试结果:

    ============开始=============
    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多陪,达到了预想的目的。

  • 相关阅读:
    三者最大实例分析
    Python eval函数
    Linux查看某个进程的线程
    将列表传递给函数
    二十四、二进制日志截取与恢复
    二十三、二进制日志事件
    二十二、二进制日志记录方式
    二十一、二进制日志介绍
    二十、错误日志
    十九、InnoDB核心参数
  • 原文地址:https://www.cnblogs.com/mimimimimi/p/4093449.html
Copyright © 2011-2022 走看看