js 计算字符频率柱形图

/**
 * 这个Node程序从标准输入中读取文本,计算文本中每个
 * 字母出现的频率,然后按使用频率降序显示一个柱形图
 * 运行这个程序需要Node 12或更高版本
 *
 * 在一个Unix类型的环境中,可以像下面这样调用它
 * node charfreq.js < corpus.txt
 */
class DefaultMap extends Map {
    constructor(defaultValue) {
        super(); //调用超类构造器
        this.defaultValue = defaultValue; //记住默认值
    }
    get(key) {
        if (this.has(key)) {
            //如果映射中有key
            return super.get(key); //从超类返回它的值
        } else {
            return this.defaultValue; //否则返回默认值
        }
    }
}

class Histogram {
    constructor() {
        this.letterCounts = new DefaultMap(0); //字母到数量的映射
        this.totalletters = 0; //字母总数
    }
    //这个函数用文本中的字母更新柱形图
    add(text) {
        //移除文本中的空白,然后将字母转换为大写
        text = text.replace(/\s/g, '').toUpperCase();
        //循环文本中的字符
        for (let character of text) {
            let count = this.letterCounts.get(character); //取得之前的数量
            this.letterCounts.set(character, count + 1); //递增
            this.totalletters++;
        }
    }
    //将柱形图转换为字符串并显示ASCII图形
    toString() {
        //把映射转换为一个[key,value]数组的数组
        let entries = [...this.letterCounts];

        //按数量和字母表对数组排序
        entries.sort((a, b) => {
            //这个函数定义排序的方式
            if (a[1] === b[1]) {
                //如果数量相同
                return a[0] < b[0] ? -1 : 1; //按字母表排序
            } else {
                //如果数量不同
                return b[1] - a[1]; //数量大的排前面
            }
        });
        //把数量转换为百分比
        for (let entry of entries) {
            entry[1] = (entry[1] / this.totalletters) * 100;
        }
        //删除小于1%的条目
        entries = entries.filter(entry => entry[1] >= 1);
        //把每个条目转换成一行文本
        let lines = entries.map(([l, n]) => {
            return `${l}:${'#'.repeat(Math.round(n))} ${n.toFixed(2)}%`;
        });
        //返回把所有行拼接起来的结果,以换行符分隔
        return lines.join('\n');
    }
}
/**
 * 这个async(返回期约的)函数创建一个Histogram对象
 * 从标准输入异步读取文本块,然后把这些块添加到柱形图
 * 在读取到流末尾后,返回柱形图
 */
async function HistogramFromStdin() {
    process.stdin.setEncoding('utf-8'); //输入进入流模式 读取命令 "<" 后面的路径文件(例如$ node charfreq.js < test2.js )Unicode字符串,而非字节
    let histogram = new Histogram();
    for await (let chunk of process.stdin) {
        histogram.add(chunk);
        console.log(chunk);
    }
    return histogram;
}
//最后这行代码是程序的主体
//基于标准输入创建一个Histogram对象,然后打印柱形图
HistogramFromStdin().then(histogram => {
    console.log(histogram.toString());
});

 

posted @ 2022-03-16 05:03  暴燥的小蓝鲸  阅读(190)  评论(0)    收藏  举报