underscope2
使用underscope来处理数据,通过chain链式运算,用起来,感觉有点像数据库的查询语句一样。能查看数据的结构,能进行数据计算,也能过滤,感觉有点像sql语句一样。当然,我也知道,下面这样一大串的查询,可能并没有什么优化,但是对一些能快速的写代码。感觉有点神奇。另外,也没有数据库的底层优化。
将目标数据导出到json格式,然后写一个页面的script变量中,如all。然后在浏览器的console中简单的进行处理来看数据的结构。
理解
underscope函数,是函数式编程的体现,而函数式编程的基础是map reduce filter这三个函数。在此基础上,再扩展成其他的形式。
而underscope的oop编程显示,利用链式调用,很方便的实现将多个操作串链在一起。
形式
- 一维变成多维
首先,利用字符串本身的split,能将一个字符串,变成一个字符串数组。对于该数组,我们还能利用chunk或者继续split到列。
利用chunk函数,将原有的数组也能升级成二维数组。
利用map函数,如
.map(x=>[x])
.chunk(1) //某些情况下跟上面等价。
- 多维变成1维
flatten,将多维数组降级成1维数组,这样方便对每个元素操作
map函数,返回每个元素(数组、或对象)的特定的值,达到降维的目的。
- 同维数据操作
filter 过滤掉返回为false的数据。另外,compact可以看作是特例。
map 进行映射。对数组中的每个元素进行操作,将操作返回的结果组合成一个新的数据。
union 数据合并。类似于php中的array_merge功能。
each遍历每个元素。
强制修改列,增加列的行数或者对象属性等。
对于2维数据,有以下:
//由于数组是按引用使用的,所以下面的,可以对某个元素进行强制修改
each(x=>x[1]=_.random(1000,9999))
//或者在元素前面两添加元素
.each(x=>x.unshift(i++)) //添加序列号 变量i的值每次都会加1
对象数组转换
object 将数组转换为对象。
pairs 将对象转换为数组。
注意点
join方法。
_.join('\n') //提示该函数并不存在
//但是如下,却能执行不报错
_(_.range(1,10)).chain()
.join('\n')
.value()
_(_.range(1,10)).chain().join //输出如下
f() {
var obj = this._wrapped;
if (obj != null) obj = method.apply(obj, arguments);
return chainResult(this, obj);
}
数据处理的例子
数据结构
[{
"orderList": [
{
"freight": ".00",
"goodsList": [
{
"name": "xxx",
........
}
],
"receiveInfo": {
"address": "",
"city": "",
......
},
"remark": "",
"sendInfo": {
"address": "",
........
},
"size": "",
"value":
.......
}
],
.....
}]
代码
_.chain(all).map(x=>x.orderList[0]).map(x=>_.keys(x)).flatten().uniq().value()
fn = x=> "$v['processTime'] = $data['processTime']".replaceAll('processTime',x)
_.chain(all).map(x=>x).map(x=>_.keys(x)).flatten().uniq().map(fn).join(';\n').value()
fn2 = x=> "$v['processTime'] = $orderList['processTime'];".replaceAll('processTime',x)
_.chain(all).map(x=>x.orderList[0]).map(x=>_.keys(x)).flatten().uniq().value()
_.chain(all).map(x=>x.orderList[0]).map(x=>_.keys(x)).flatten().uniq().map(fn2).join('\n').value()
fn3 = x=> "$v['recv_processTime'] = $receiveInfo['processTime'];".replaceAll('processTime',x)
_.chain(all).map(x=>x.orderList[0].receiveInfo).map(x=>_.keys(x)).flatten().uniq().value()
_.chain(all).map(x=>x.orderList[0].receiveInfo).map(x=>_.keys(x)).flatten().uniq().map(fn3).join('\n').value()
fn4 = x=> "$v['send_processTime'] = $sendInfo['processTime'];".replaceAll('processTime',x)
_.chain(all).map(x=>x.orderList[0].sendInfo).map(x=>_.keys(x)).flatten().uniq().map(fn4).join('\n').value()
_.chain(all).map(x=>x.orderList[0].goodsList).map(x=>_.keys(x)).flatten().uniq().value()
_.chain(all).map(x=>x.orderList[0].goodsList).value()
_.chain(all).map(x=>x.orderList[0].goodsList[0].name).uniq().join(',').value()
_.chain(all).filter(x=>x.orderList[0].goodsList[0].name == '假发').map(x=>x).value()
_.chain(all).map(x=>x.orderList[0].threeSegmentCode).sort().uniq().join('\n').value()
// 强大的统计功能,真厉害 countBy 返回统计的名称
_.chain(all).map(x=>x.orderList[0].status).countBy(x=>x||'none').value()
//多个map一起用,每段一种含义,方便理解。
_.chain(all).map(x=>JSON.parse(x.json_data)).map(x=>x.orderList[0].receiveInfo).map(x=>_.keys(x)).flatten().uniq().value()
代码片段
其他例子:
_(_.times(900,x=>_.random(1,100))).chain().countBy(x=>'key-'+x).map(x=>x).sort((x,y)=>x-y).value()
统计字母:
_(_.keys(_))
.chain()
.map(x=>x.toUpperCase())
.map(x=>x.split('')) //升级成多维数据
.flatten() //降级成1维数组
.countBy() //统计
.map((x,y)=>([y,x])) //将对象转换为 [[],[]] 格式,本意是想转换成[{},{}]
.sort((x,y)=>(x[1]-y[1])) //排序
.last(10) //最到最大的几个。
//.object()
.value()
对每列进行操作
_(data.split(/\s+/)).chain()
.chunk(3)
.each(function(x){
mapping = {
VARCHAR2:'varchar',
DATE:'date',
CHAR:'varchar'
}
x[0]=x[0].toLowerCase()
x[1] = mapping[x[1]]
})
.map(x=>x[0]+ ' '+ x[1]+ '('+x[2]+'),')
//.map(x=>`${x[0]} ${x[1]}(${x[2]})`) //或
.join('\n')
.value()
快速解析成json对象
_(data.split(/\s+/))
.chain()
.chunk(2)
.object()
.value()
产生时间格式序列
_(_.range(100))
.chain()
.map(x=>24*3600*1000*x)
.map( x=>new Date((new Date('2021-01-01 00:00:00').getTime()+x) ) )
.map(x=>x.format('yyyy-MM-dd hh:mm:ss'))
.win(4)
.tpl('start :{0} end:{3}')
.join('\n')
.value()
查找最多的文字
words = _(data.split(''))
.chain()
.countBy(x=>x||'none')
.map((x,y)=>([y,x])) //将对象转换为 [[],[]] 格式,本意是想转换成[{},{}]
.sort((x,y)=>(x[1]-y[1])) //排序
.reverse()
.filter(x=>(x[0]!=',' && x[0]!='。' ) )
.first(10) //最到最大的几个。
//.object()
.map(x=>x[0])
.value()
words = _(data.split(''))
.chain()
.countBy(x=>x||'none')
.map((x,y)=>([y,x])) //将对象转换为 [[],[]] 格式,本意是想转换成[{},{}]
.sort((x,y)=>(x[1]-y[1])) //排序
.reverse()
.filter(x=>(x[0]!=',' && x[0]!='。' ) )
.first(10) //最到最大的几个。
//.object()
.map(x=>x[0])
.value()
//找出包含最多字的话
_(data.split(/[,。\n]/))
.chain()
.filter(x=>_.any(_.map(words,y=>x.indexOf(y)>-1)))
.compact()
.join('\n')
.value()
//.length
过滤包含特定字符串的行,
_(data.split('\n')).chain()
.filter(x=>_.any(['sendId','recvId','shipId'],y=>x.indexOf(y)>=0) )
.map(x=>[x]) // 更简单的形式 .chunk(1)
.value();
其中filter函数,柯里化的形似如下:
(x,z)=>_.any(z,y=>x.indexOf(y)>=0)
上述文本样本如下:
array (
'sendId' => 'KRFqCgzFt0U4ypEpK01X==',
'recvId' => 'POjx+qOq+QJrBKUcYqL/==',
'shipId' => '43111867526',
)all_ships_phone_used_topic 42
array (
'sendId' => '7HVD6VbL2jTweXGBa1E2==',
'recvId' => 'rjEDBL/cdJ+b6qHXa2hk==',
'shipId' => '46063065601',
)all_ships_phone_userId_top
格式化显示对应的值
_(data.split('\n')).chain()
.filter(x=>_.any(['sendId','recvId','shipId'],y=>x.indexOf(y)>=0) )
.map(x=>x.split("=> '"))
.map(x=>x[1])
.map(x=>x.substring(0,x.length - 2))
.chunk(3)
.value();
对于上述的3个map,可以合成一个map,但是需要倒序(因为合成函数的顺序,卡了半天):
.map(
_.compose(
x=>x.substring(0,x.length - 2),
x=>x[1],
x=>x.split("=> '")
))
添加分类
数据格式如
安徽
http://www.tianqihoubao.com/weather/province.aspx?id=340000
安庆
anqing
蚌埠
bangbu
亳州
bozhou
我们期待如下输出:
1 安徽 安庆 anqing
2 安徽 蚌埠 bangbu
3 安徽 亳州 bozhou
对应的代码为:
cur=''
_(data.split(/\s+/))
.chain()
.chunk(2)
.each(function(x,index,obj){
if(x[1].length > 50) cur = x[0] //找到特殊的记录
obj[index] = [cur,...x]
})
.filter(x=>x[2].length< 50 )
.value()
排序用法
排序注意用法,对象数组,直接用普通的字段名称,也能使用回调函数(注入一个参数)。如下的示例。
这里错误的示例是,(搞错了用法)://.sortBy((x,y)=>x.create_time>y.create_time?1:-1)
_(JSON.parse(data))
.chain()
.sortBy('create_time') //默认asc
.reverse() //desc
.map(x=>_.values(x))
.value()
pg结果输出优化:
_(data.split('\n')).chain()
.map(x=>x.split('|'))
.map(x=>_.map(x,y=>y.trim()))
.map(x=>x.join('\t'))
.join('\n')
.value()
导出到表格
使用下面的方式,生成的字符串复制到表格,能粘贴为表格。但是,如果实际上,直接点表格展示,粘贴就ok了。
data = JSON.parse(data)
_(data)
.chain()
.map(x=>_.values(x))
.map(x=>x.join('\t'))
.join('\n')
.value()
排查异常
根据异常代码的行数,用split(‘\n\n\n\n’) 来分隔,生成每次异常的数组。而对于一次异常,再次分隔成多行。根据一次异常日志的行数,则可以找到特定的异常。
正则匹配字符串
data = data.split('\n')
_(data)
.chain()
.map(function (x) {
res = [];
var reg1 = /`(.*?)`/g
reg1.test(x)
res.push(RegExp.$1)
var reg2 = /COMMENT\s+'(.*?)'/g
reg2.test(x)
res.push(RegExp.$1)
return res
})
.tpl(`
- in: formData
name: {0}
type: string
required: false
description: {1}`)
.join('')
.value()
正则匹配
Time: 248721.958 ms
SELECT 483512499
Time: 0.731 ms
统计上面的合
data = data.split('\n');
_(data)
.chain()
.map(function(x){
var reg1 = /Time: (.*?) ms/g
//注意下面,匹配成功,则返回匹配的值,因为,即使匹配不成功,可能用上次的值。
return reg1.test(x)?RegExp.$1:0;
})
.map(x=>parseInt(x))
.sum()
.value()