改变

向前走,别害怕 每刻

随记

昨天被问到js如何统计字符串出现频率最高字母的问题,而后今天一时兴起来实践一下 01.03.2018

假如说这段字符串是:"North Korea has reopened a hotline to South Korea, almost two years after it was disabled on the orders of leader Kim Jong-un."

我其实首先想到的是map,reduce来解决,后面细想了一下,不对啊,内存没有记录每个字母对应的次数啊。但是有种欲罢不能的探究欲望想用这样的方式来实现。

首先肯定要先把这段话给分割成数组,所以 str.split(''); 这句代码是跑不掉的。

然后我就开始死磕了,把map用来映射了每个字母,再把字母给分别计数,然后用一个对象来把字母和出现次数的键值对给包含起来。接着想想,欸?那reduce呢?对象没有reduce啊...

一脸尴尬...

我就开始思考reduce其本质,因为不管怎么样,我需要reduce做的操作其实就是把某个数组给规约出来,但是这个数组我不仅要他含有字母出现的次数,而且还要他含有那个字母。

那二维数组呢?二维数组我还不如用对象呢...因为对象的键值对方式很方便啊...

我想如果为了要用一个reduce而加入那么多的数组索引取值,不值得。于是乎我就直接使用对象好了,reduce用不上就不用吧。

str.split('') 分割之前先声明一个公共对象 let a = {};

接着给分割后的数组写map方法 let a = {}; str.split('').map(x=>{})

其实我用对象的话,我只需要知道有没有那个字母键,没有我就加入一个字母键,初始他的值为1;如果有,我就将这个字母键对应的值累加1。

然后形成代码就是 let a = {}; str.split('').map(x=>{ if(a[x]) a[x]+=1; else a[x]=1; });

我就获取到了一个包含字母及其出现次数键值对的对象。现在的关键就是,我如何将他们排序并且将这个字母给读出来?

我的想法是,先将值从大到小倒序排列,然后取最大的那一个,然后再遍历对象中每个字母键的值,看是否与之相等,相等便输出这个字母。

要分别遍历值的话,对于对象有个办法就是通过 Object.values(a); 来获取对象中所有值组成的一个数组。

对于键也是一样的道理,通过 Object.keys(a); 来获取。

最后形成代码就是 let a = {}; str.split('').map(x=>{ if(a[x]) a[x]+=1; else a[x]=1; }); Object.keys(a).forEach(x=>{if(a[x]===Object.values(a).sort().reverse()[0]) console.log(x);});

虽然这么做可以解决问题,但是有两个问题我没法解决,一个是效率优化,一个是最高次数有两个字母时。

我先把他封装成函数 function mr_str(str){ let a = {}; str.split('').map(x=>{ if(a[x]) a[x]+=1; else a[x]=1; }); let r=''; Object.keys(a).forEach(x=>{if(a[x]===Object.values(a).sort().reverse()[0]) r=x;}); return r; }

对于最高字数有两个字母时,把方法中的r类型改为数组[],并且在遍历时,push进入数组中,然后返回该数组即可。

就改动了一下 function mr_str(str){ let a = {}; str.split('').map(x=>{ if(a[x]) a[x]+=1; else a[x]=1; }); let r=[]; Object.keys(a).forEach(x=>{if(a[x]===Object.values(a).sort().reverse()[0]) r.push(x);}); return r; }

效率的话,只能来用时延数据来说明了。但是我目前还没有对照方法啊...

到时候想好了再来更吧...

烛火

通过ngrok穿透内网,用Python写服务端,爬虫能够帮我抓取到我想知道的最新消息 06.2017

了解更多