Java、Scala、Python ☞ 本地WordCount词频统计对比

版权声明:有问题的请留言 喜欢的请给个赞 --------------------------------不定时会更新,因为学习,所以快乐,因为分享,所以便捷!转载请标注出处,哈哈! https://blog.csdn.net/Appleyk/article/details/82460259

需求:模拟MapReduce,对磁盘文件(N个)里面的单词进行词频统计(统计每个单词在文件中出现的次数)

区别:计算采用本地模式(单线程),只是模拟Map和Reduce的联合过程,并不单独分离出两个任务(方法)

目的:通过不同语言实现词频统计功能,并对比各自的风格

一、数据样例(Samples)

百度网盘:wordcount.rar

主要是为了测试,所以数据尽量怎么简单怎么来,也可以自定义样例数据

二、思路

三、编程实现

(1) Java demo实现

package com.appleyk.java;

import sun.applet.Main;

import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description
 * @Author Appleyk
 * @Blob https://blog.csdn.net/appleyk
 * @Date Created on 上午 8:44 2018-9-6
 */
public class JWordCount {

    // main方法快捷键  :  psvm
    public static void main(String[] args) throws  Exception{

        System.out.println("================Java=============");
        String path = "F:\\wordcount";
        File dirFile = new File(path);
        // file数组
        File[] files = dirFile.listFiles();
        for (File f : files) {
            System.out.println(f);
        }
        // file数组转List
        List<File> fileList = Arrays.asList(files);
        Map<String,Integer> wordMap = new HashMap<>();
        fileList.forEach(file->{
            try{
                BufferedReader bReader = new BufferedReader(new FileReader(file));
                // 循环读取行
                String line = "";
                while((line=bReader.readLine())!=null){
                    String[] lines = line.split(" ");
                    for (String word : lines) {
                        if(wordMap.containsKey(word)){
                            int value = wordMap.get(word);
                            wordMap.put(word, value+=1);
                        }else{
                            wordMap.put(word, 1);
                        }
                    }
                }
                bReader.close();//释放资源
            }catch (IOException ex){
                System.out.println(ex.getMessage());
            }
        });
        System.out.println("=====Java词频统计结果打印输出======");
        System.out.println(wordMap);
        for(Map.Entry<String,Integer> result:wordMap.entrySet()){
            System.out.println("单词:"+result.getKey()+",个数:"+result.getValue());
        }
    }
}

Java大家都是很熟悉了吧,因此写起来demo毫不费劲,总体下来还是一气呵成的,代码不做过多解释,唯一需要说明的就是demo中采用了Java8的特性 -- forEach(很方便)

我们看下执行的结果:

================Java=============
F:\wordcount\1.txt
F:\wordcount\2.txt
F:\wordcount\3.txt
F:\wordcount\4.txt
=====Java词频统计结果打印输出======
{a=8, b=8, c=12, d=8, e=8, f=4}
单词:a,个数:8
单词:b,个数:8
单词:c,个数:12
单词:d,个数:8
单词:e,个数:8
单词:f,个数:4

(2) Scala demo实现

package com.appleyk.scala

import java.io.File
import scala.io.Source

object SWordCount{
  def main(args: Array[String]): Unit = {

    System.out.println("================Scala=============")
    val path = "F:\\wordcount"     //目录url
    val dirFile = new File(path)   //混搭Java代码,new一个file对象,该对象是一个目录
    val files = dirFile.listFiles  //列出file目录下的所有文件【Java中是一个file数组】

    //遍历files对象【数组】
    for(file <- files) println(file)

    // 将files对象转化为List集合
    val fileList = files.toList

    // Scala中使用不可变的映射。如果想使用可变集,必须明确地导入scala.collection.mutable.Map类
    // wordMap变量不可变,但是其指向的却是一个可变的Map集合,键值对 --> key:String -> value:Int
    val wordMap = scala.collection.mutable.LinkedHashMap[String,Int]()

    // 遍历【非常恐怖,三次foreach搞定词频统计!!!】
    fileList foreach(file=> Source.fromFile(file).getLines() //从file里面读取二进制流,并获取流的行数据列表
      .foreach(line=>line.split(" ") // 每一行数据根据空格分割成words列表
      .foreach(word=>{
           //判断word【单词】是否在map里
           if(wordMap.contains(word)){
               wordMap(word)+=1      // 有的话,计数器(key对应的value)+1
           }else{
               wordMap+=(word -> 1)  // 否则的话,将单词word加进map集合中,并初始化value=1
           }
      })
      ))
     printf("=====C编码风格的输出【词频统计结果打印】======%s","\n")
     System.out.println(wordMap)
     for((k,v) <- wordMap) printf("单词:%s,个数:%d \n",k,v)
  }
}

       由于Scala运行于Java平台(Java虚拟机)上,并兼容现有的Java程序,因此,我们在编码的时候也可以混搭着Java的代码;同时,我们对比发现,Scala的编码风格真的很随意,可以【对象 空格 foreach】也可以使用【对象.foreach】的方式进行列表的遍历,同时,其支持lambda表达式【匿名函数】,结合foreach,我们可以利用很少的代码将整个需求给实现出来,而且map集合的for循环打印出key-value键值对也是很轻松的,比较Java,Scala确实很棒,博主在学习Scala语言的时候,发现其和Python的语法有些像,所谓语言都是相通的,学好一门语言,其他语言基本上都能很快入手,不多说,我们看下Scala运行的效果:

================Scala=============
F:\wordcount\1.txt
F:\wordcount\2.txt
F:\wordcount\3.txt
F:\wordcount\4.txt
=====C编码风格的输出【词频统计结果打印】======
Map(a -> 8, b -> 8, c -> 12, d -> 8, e -> 8, f -> 4)
单词:a,个数:8 
单词:b,个数:8 
单词:c,个数:12 
单词:d,个数:8 
单词:e,个数:8 
单词:f,个数:4 

需要说明下,使用Map集合,最后的结果是乱序的,因此demo中使用了LinkedHashMap【有序Map】

(3) Python demo实现

#!/usr/bin/env Python3
# -*- encoding:utf-8 -*-

import  os   #导入os模块,并使用该模块调用系统命令,获得路径,操作系统的类型等

if __name__=="__main__":

    print("================Pyhton=============")
    path="F:\\wordcount"      #目录url
    filenames = os.listdir(path) #os.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表,注意是名字

    #拿到文件的全路径名称集合
    filefullnames = [os.path.join(path,filename) for filename in filenames]

    for name in filefullnames:
        print(name)

    #遍历文件名列表+完整路径拼接+生成文件对象列表
    fileList = [open(filefullname) for filefullname in filefullnames]

    #上面的生成式的当时等价于下面的for代码块
    # for filename in filenames:
    #     filename = os.path.join(path,filename)    #文件完整路径拼接
    #     fileList.append(open(filename,'r'))       #添加文件对象


    wordMap = {} #定义一个单词的字典【dict】集合

    #遍历文件对象列表
    for file in fileList:
        for line in file: #读取文件中的每一行
           words = line.strip('\n').split(" ") #消除换行符,并对每一行数据进行空格分割
           for word in words: #遍历单词列表
               if wordMap.get(word) is not None: #如果字典表里面包含了单词word
                   wordMap[word]+=1  #出现频率+1
               else:
                   wordMap[word]=1   #添加一个单词,初始化频率为1
        file.close() #释放资源


    print("=====Python词频统计结果打印输出======")
    print(wordMap)
    for key in wordMap.keys():
        print("单词:%s,个数:%d" %(key,wordMap.get(key)))

        如果说Scala在对变量的类型没有太大要求的话【val:不可变,var:可变,但是类型是自动匹配的】的话,那么Python对变量简直就是没有要求,你不需要给变量指定什么String类型、Int类型或者是指定变量是val可变的还是var不可变的,其变量的赋值操作就是变量声明和定义的过程,因此,在声明一个变量的时候,必须先赋值

       

        而且Python有列表生成式,可以很方便的根据条件生成我们最终想要的结果列表,如下:

        利用列表生成式再结合条件过滤,生成一个偶数序列

         demo中,我们利用列表生成式(List generation)的特性拿到了文件的完整路径列表,如下

更多生成式的用法,可以参考我的博文:Python3学习(9)--列表生成式(List generation)

.....................................................话不多说,我们直接运行demo,看一下pyhton的执行情况

================Pyhton=============
F:\wordcount\1.txt
F:\wordcount\2.txt
F:\wordcount\3.txt
F:\wordcount\4.txt
=====Python词频统计结果打印输出======
{'a': 8, 'b': 8, 'c': 12, 'd': 8, 'e': 8, 'f': 4}
单词:a,个数:8
单词:b,个数:8
单词:c,个数:12
单词:d,个数:8
单词:e,个数:8
单词:f,个数:4

四、最后

 通过对比,我们可以看出,在代码简洁程度上,Scala和Python那是旗鼓相当啊,但如果只能选一个的话,那非Pyhton莫属了!

 而且,Python写起demo来比较嗨皮,,Java则是中规中矩的老大哥,Scala由于是分布式计算框架Spark的实现语言,因此,

 Scala我们可以稍微了解一下,语言都是相通的,建议多掌握几门辅助语言,这样有利于日常工作的顺利开展

猜你喜欢

转载自blog.csdn.net/Appleyk/article/details/82460259