使用Java进行数据预处理---根据CSV格式的数据的第一列作为key,若第一列的key相等,则将相同的key后面的第二 ...

论坛 期权论坛 脚本     
匿名技术用户   2020-12-31 00:58   107   0

一:题目--文章需要解决的问题

题目的意思也可以表述为:

将一堆项集数据,根据数据的第一列值是否相同,来判断第二列的值是否该进行合并,相当于使之变成序列数据集。

题目的样例1表述

输出的数据格式 (可以先用Excel进行升序处理,便于userID相等的呆在一起)

a,v1
a,v2
b,v3
a,v4
c,v3
c,v5

数据预处理后后的结果:

a,v1|v2|v4
b,v3
c,v3|v5

题目的样例2表述:

userid value

0 1

0 3

0 5

1 2

1 4

数据预处理后的结果:

userid value

0 1 3 5

1 2 4

二:题目解决的思路

主要判断当前行的userid是否与上一行的userid相等,若相等,则进行添加,使之成为一行即成为一个单独的序列;若不想等,则新起一行,成为一个新的序列的开头数据。

借助list,hashmap,map的value,key等Java的数据结构进行数据操作;借助stringBuffer,StringBuilder,BufferedWriter,BufferReader等进行文件相关数据读取,写入等操作;利用泛型方法进行数据的拼接,利用迭代器进行集合的遍历。

三:具体代码及注释

package temp;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class mosaicFile2 {
    public static void WriteCSV2(File csv, StringBuffer sBuffer) {
        BufferedWriter bw;
        /*
         * BufferedWriter类:用于加快写入的速度。
         *      构造方法: BufferedWriter bf = new BufferedWriter(Write out)
         *      主要方法: void write(): 写入单个字符
         *               void newLine(): 写入一个行分隔符
         *               void close(): 关闭该流
         *      
         *               */
        try {
            bw = new BufferedWriter(new FileWriter(csv, true));
            // 添加新的数据行
            bw.write(new String(sBuffer));
            bw.newLine();
            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        } // 附加
    }

    public static void  ReadCSV2(FileReader fr){
         try {  
              //key,values
             BufferedReader reader = new BufferedReader(fr);
             /*
              * bufferedReader类:为了提高读的效率而设计的一个包装类,它可以包装字符流;可以从字符输入流中读取文本,
              *                   缓冲各个字符,从而实现字符,数组和行的高效读取
              *        构造方法:BufferedReader br = new BufferedReader(reader in)
              *        常用方法:int read() :读取单个字符
              *                 String readLine(): 读取一个文本行
              *                 void close():关闭该流,并释放与该流相关的所有资源
              */
                ///reader.readLine();//第一行信息,为标题信息,不用,如果需要,注释掉 
             reader.readLine(); //因为我们的csv文件的第一列有列属性(即列名称)
             String line = null;  
             String flag="-1";  //作为一个标志,即上一行的第一列数值的值(
             //没有后续判断当前行与上一行是否相等的作用,只起到启动第一行的作用)
             StringBuffer all=new StringBuffer();
             /*
              * StringBuffer :
              *       构造方法:StringBuffer a = new StringBuffer()
              *       初始化方法:StringBuffer a = new StringnnnnBuffer(“java”);
              *               1)是一个string的缓冲区,和string不同的是,它可以被修改。StringBuffer在任意时刻都有
              *               一个任意的字符串序列。
              *               2)StringBuffer继承了抽象类AbstractStringBuilder,它本质上是一个字符数组。
              *       常用方法:append(String str): 把任意类型添加到字符串缓冲区里面,并且返回字符串缓冲区本身
              *               insert(int offset, String str): 插入
              *               delete(index): 删除指定位置的字符
              */
              String lastUserId="";   //初始化为空
              int count=0;
              //  Map<String, List<String>> map1=new HashMap<>();
              Map<String, String> map=new HashMap<>();
              /* Map
               * 1)java自带了各种map类.HashMap是最常用的map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,
               * 具有很快的访问速度
               * 2)Map是个接口,HashMap是它的实现类 
               * 3)Map的初始化: Map<String,String> map = new HashMap<String,String>();
               *        插入元素 map.put("key1","value1")
               *        获取元素 map.get("key1")
               *        移除元素 map.remove("key1")
               *        清空map map.clear()
               * 
               */
              List<String> list=new ArrayList<>();
              /*
               * List  ArrayList
               * 1)List集合是一个容器,可以添加各种各样的数据.
               * 2)使用此接口能够精确地控制每个元素的插入位置。用户能够使用索引(索引即元素爱list中的位置,类似于数组的下标)
               * 3)方法:   void add(String item)  // 依次往后添加元素
               *            void add(String item, int index)  //在指定位置处添加元素
               *            void remove(int position)  //删除第几个元素,索引从0开始
               *            list.clear():删除列表中所有元素
               */
                System.out.println("输出通过list处理后的数据:");
                while((line=reader.readLine())!=null){
                    String item[] = line.split(",");//CSV格式文件为逗号分隔符文件,这里根据逗号切分 
                    // 把该行的数据分成两列,第一列放在item[0]里面;第二列放在item[1]里面
                    if(item!=null){
                     //System.out.println("yewei"+item[0]+" "+item[1]);
                     if (flag=="-1") {   //最开始flag已经被初始化为1了。
                      list.add(item[1]);
                      //lastUser=item[0];
                      flag="-2";
                      lastUserId=item[0];
                     }
                     else {
                      if (lastUserId.equals(item[0])&&list.size()>=1) {
                       // 判断当前这一行的userid与上一行的userid是否相等,当前的list的长度是否大于1
                       // 只有当上面两个条件都满足时候,才会把第二列的数据进行添加
                       list.add(item[1]);
                      }else {
                       if (!lastUserId.equals(item[0])) {
                        // 当上一行的userid与当前行的userid不相等时候,说明当前行是一个新用户
                        
                        System.out.println(lastUserId+" "+list);//一行一行地处理
                        //别忘了list输出里面的数据会自动有[]和逗号呀,和数组一样
                        map.put(lastUserId, toString(list, ' '));  
                        /*  调用后面定义的toString的这个泛型,即把list里面的元素放进map里面,并且元素
                            之间使用符号"|"隔开.
                            注意:这里面为什么要使用map.put呢?这是便于我们在运行对话框里面可以直接输出,
                            即在内存中可以直接输出,其实与写文件进行保存结果的关系不大,这将由下一行代码完成。
                        */
                        //all.append(lastUserId+","+toString(list, ' '));
                        all.append(toString(list, ' '));
                        //我们在这儿把第一列的同一userid和它对应的第二列的数据添加到all这个StringBuffer
                        //WriteCSV2(new File("result01.csv"),all); 
                        //WriteCSV2(new File("result01.txt"),all); 
                        //WriteCSV2(new File("res114.csv"),all); 
                        //WriteCSV2(new File("res114.txt"),all); 
                        WriteCSV2(new File("finalresult.csv"),all); 
                        WriteCSV2(new File("finalresult.txt"),all); 
                        // 把all里面的数据写入到指定的文件里面,依旧是scv格式
                        all.setLength(0);//进行清空,便于后面可以继续使用,避免了多次创建StringBuffer的all。
                        //map.put(string, list);
                        lastUserId=item[0];  //更新lastUserId,即把当前行的lastUserId赋值给上一个。
                        list.clear();  //释放,因为新一个的UserID来临
                        //System.out.println(list.size());
                        count++;   //统计有多少个不同的userID
                        list.add(item[1]);  //新出现的一个userId添加到list(此时list里面就一个元素喔)
                       }
                      }
                     }
                    }
                }  
                System.out.println("此时已经完成写入文件操作,并且map里面也存储完数据");
                System.out.println("接下来我们输出map里面暂时存储的数据");
                for (Map.Entry<String, String> entry : map.entrySet()) {
                 /*  Entry:
                  *   map中采用entry内部类表示一个映射项。映射项包括key和value。一个entry就是一个键值对.
                  *      map.entry里面包含getKey()和getValue()方法
                  *  entrySet
                  *      entrySet是键值对的集合,set的类型是map.entry,一般可以通过map.entrySet()得到
                  *  map的遍历方法:
                  *      for(Map.Entry<String,String> entry:map.entrySet()) 
                  *  ***** 特别注意理解:map中一个键对应是一个键值,但是这个键值可以是string类型呀,因此在成为键值的前面
                  *        可以利用泛型方法进行第二列值的append,append结束后再放入map里面充当键值。
                  */
                 System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
                }
                System.out.println("输出map里面的键值对的数量 "+map.entrySet().size());
                System.out.println( "统计出userId的数量:"+"count:="+count);
            } catch (Exception e) {  
                e.printStackTrace();
                //System.out.println("File Complete!!");
            }  
    }
    
    public static <T> String toString(List<T> list,char ch) {  //定义一个T类型,返回值是String类型。括号中为参数
    /*
     * Java泛型: 也被称为模版编程
     *     本质上是参数化类型,也就是说所操作的数据类型被指定为一个参数。举例理解,假设有这样的一个需求,写一个
     *     排序算法,能够对整型数组,字符串数组,甚至任何其他类型的数组进行排序--->这个时候就可以使用泛型,写
     *     一个泛型方法来对对象数组排序,任何调用该泛型方法就可以对整型数组,祖父处数组排序来
     * 泛型和多态的区别:
     *     泛型编程是编译期替换;多态则是运行期作类型转换
     * 泛型方法(代码是如何的?):
     *     该方法在调用时,可以接收不同类型的参数;所有泛型方法都有一个类型参数声明部分,该类型参数声明部分在方法
     *     返回类型之前(eg <t>在void/String之前)。  每一个类型参数声明部分包含一个或者多个类型参数,参数
     *     间用逗号隔开,其中一个是泛型参数,也被称为一个类型参数eg:List<T> list
     */
        Iterator<T> it = list.iterator();
        /*
         * java迭代器:
         *       由于集合的内部结构不同,很多时候可能不知道该怎样去遍历一个集合中的元素,因此引入来迭代器模式。
         *  迭代器的使用:
         *       1)使用方法iterator() 要求集合返回一个iterator,iterator将准备好返回集合的第一个元素
         *       2)使用next()获取集合的下一个元素
         *       3)使用hasNext()检查集合中是否还存在元素(为boolean,存在会返回true)
         *       4)使用remove()将迭代器新近返回的元素删除。
         * 注意:如果迭代器的指针已经指向了集合的末尾,那么如果再调用next()会返回NoSuchElementException异常
         * 如何定义(list)迭代器:
         *  Iterator<type> temp = list.iterator();  //获取list专属的迭代器
         */
        if (! it.hasNext())
            return "";  //如果集合是空的,则返回空;如果集合不是空的,则接着往下走,执行下面的语句
        //StringBuilder sb = new StringBuilder();
        StringBuffer sb = new StringBuffer();
        /*
         * StringBuilder:
         * 声明方式:StringBuilder sb = new StringBuilder(); //无参数构造方法
         *     StringBuffer 字符串变量(线程安全)
               StringBuilder 字符串变量(非线程安全)
         */
        // sb.append('[');
        for (;;) {
            T e = it.next(); //获取集合中的下一个元素
            //sb.append(e == this ? "(this Collection)" : e);
            sb.append(e);   //把获取的元素添加到sb这个StringBufrrer里面
            if (! it.hasNext())  //检查集合中是否还存在元素
               // return sb.append(']').toString();
                return sb.toString();   //如果不存在则结束吧?
           // sb.append('*').append(' ');
            sb.append(ch);   // 如果集合中还存在元素,则插入一个符号标志,符号标志就是ch对应的值。
        }
    }
    
    public static void main(String[] args) throws Exception{
     ReadCSV2(new FileReader("data02.csv"));  //需要处理的数据
     //ReadCSV2(new FileReader("writers.csv"));
            // /Users/mac/Desktop/study/Programme/python/project202004/mooc/dataprocessing/data01.csv
     //ReadCSV2(new FileReader("Users\\mac\\Desktop\\study\\Programme\\python\\project202004\\mooc\\dataprocessing\\data01.csv"));
    }
}

四:总结

要学会利用Java的一些现成方法进行数据的预处理操作

五:参考

参考的博客

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP