• lodash用法系列(4),使用Map/Reduce转换


    Lodash用来操作对象和集合,比Underscore拥有更多的功能和更好的性能。

    官网:https://lodash.com/
    引用:<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
    安装:npm install lodash

    首先通过npm安装lodash:
    npm i --save lodash

    在js文件中引用lodash:
    var _ = require('lodash');

    本系列包括:

    lodash用法系列(1),数组集合操作
    lodash用法系列(2),处理对象 
    lodash用法系列(3),使用函数 
    lodash用法系列(4),使用Map/Reduce转换  
    lodash用法系列(5),链式 
    lodash用法系列(6),函数种种 

    ■ 对象的集合,留下对象中某个字段的集合

    var collection = [
        {name: '', age:45}
    ];
    
    _.pluck(collection, 'age');

    也可以这样写:

    _.map(collection, 'age');

    ■ 对象的集合,留下想要的字段们

    var collection = [
        {frist:'',last:'',age:23},
        ...
    ];
    
    _.map(collection, function(item){
        return _.pick(item, ['first','last']);
    })


    ■ 对象的集合,排除不想要的字段们,不想要的字段作为参数传递

    var collection = [
        {first:'',last:'',age:19},
        ...
    ];
    
    _.map(collection, function(item){
        return _.omit(item, 'first');
    })

    ■ 对象的集合,排除不想要的字段们,通过函数

    var collection = [
        {first:'',last:'',age:19},
        ...
    ];
    
    //key 字段名称
    //value 字段对应的值
    function invalidAge(value, key){
        return key === 'age' && value < 40;
    }
    
    _.map(collection, function(item){
        reutrn _.omit(item, invalidAge);
    });

    ■ 对象的集合,给对象元素添加新的字段,根据现有字段计算而得

    var collection = [
        { name: 'Valerie', jqueryYears: 4, cssYears: 3 },
        { name: 'Alonzo', jqueryYears: 1, cssYears: 5 },
        { name: 'Claire', jqueryYears: 3, cssYears: 1 },
        { name: 'Duane', jqueryYears: 2, cssYears: 0 }
    ];
    
    var result = _.map(collection, function(item){
       return _.extend({
           experience: item.jqueryYears + item.cssYears,
           speciality: item.jqueryYears >= item.cssYears ? 'jQuery' : 'CSS'
       }, item);
    });
    
    //[ { experience: 7,speciality: 'jQuery',name: 'Valerie',jqueryYears: 4,cssYears: 3 },...]
    console.log(result);

    ■ 使用map方法一个不易发现的错误

    var app = {},
        collection = [
            { name: 'Cameron', supervisor: false },
            { name: 'Lindsey', supervisor: true },
            { name: 'Kenneth', supervisor: false },
            { name: 'Caroline', supervisor: true }
        ];
    
    app.supervisor = _.find(collection, {supervisor:true});
    
    //{ supervisor: { name: 'Lindsey', supervisor: true } }
    console.log(app);
    
    _.map(collection, function(item){
       return _.extend(item, {supervisor: false});
    });
    
    //{ supervisor: { name: 'Lindsey', supervisor: false } }
    console.log(app);


    以上,使用map对collection集合操作,重写supervisor字段的值,居然也把app对象的supervisor字段值也重写了。

    ■ map方法使用内置函数,计算每一个集合元素的大小

    var collection=[
        [1,2],
        [1,2,3],
        {first:1, second:2},
        {first:1, second:2,third:3}
    ];
    
    var result = _.map(collection, _.size);
    
    //[ 2, 3, 2, 3 ]
    console.log(result);

    ■ map方法使用内置函数,获取每个集合元素中的最小值

    var source = _.range(1000),
        collection=[
            //sample从集合中获取一个或n个元素
            _.sample(source,50),
            _.sample(source,100),
            _.sample(source,150)
        ];
    
    //[ 12, 44, 0 ]
    console.log(_.map(collection, _.min));

    ■ map方法使用内置函数,针对集合元素依次调用多个方法

    var collection = [
        [ 'Evan', 'Veronica', 'Dana' ],
        [ 'Lila', 'Ronald', 'Dwayne' ],
        [ 'Ivan', 'Alfred', 'Doug' ],
        [ 'Penny', 'Lynne', 'Andy' ]
    ];
    
    var result = _.map(collection, _.flowRight(_.first, function(item){
        return _.sortBy(item);
    }));
    
    //[ 'Dana', 'Dwayne', 'Alfred', 'Andy' ]
    console.log(result);


    以上,flowRight方法会依次调用其参数方法,先给每个一个元素内的元素排序,然后取出元素中的元素中的第一个。

    ■ 对集合元素依次使用多个方法

    var collection = [
        { name: 'Karl', enabled: true },
        { name: 'Sophie', enabled: true },
        { name: 'Jerald', enabled: false },
        { name: 'Angie', enabled: false }
    ];
    
    var result = _.flowRight(
        _.partialRight(_.map, 'name'),
        _.partialRight(_.filter, 'enabled')
    )(collection);
    
    
    //[ 'Karl', 'Sophie' ]
    console.log(result);


    以上,对集合依次使用了filter和map方法。

    ■ 获取对象的所有键值

    var object = {
        first: 'Ronald',
        last: 'Walters',
        employer: 'Packt'
    };
    
    var result = _.map(_.sortBy(_.keys(object)), function(item){
        return object[item];
    })
    
    //[ 'Packt', 'Ronald', 'Walters' ]
    console.log(result);

    以上,_.keys(object)获取对象的所有键,_.sortBy(_.keys(object))对所有键排序,然后根据键获取所有元素。

    ■ 创建唯一的自增编号

    var result = _.uniqueId('user-');
    var result2 = _.uniqueId('user-');
    console.log(result);//user-1
    console.log(result2);//user-2

    以上,通过_.uniqueId('user-');创建的编号是唯一、自增的。

    ■ 从两个具有相同键、相同键数量的对象中,取出对应的键、键值合并成一个新的对象,新的对象作为数组元素

    ar users = {},
        prefereces = {};
    
    _.each(_.range(100), function () {
        var id = _.uniqueId('user-');
        users[id] = {type: 'user'};
        prefereces[id] = {email: !!(_.random())}
    });
    
    //users:{ 'user-1': { type: 'user' },'user-2': { type: 'user' },...}
    //preference:{ 'user-1': { email: false },  'user-2': { email: true }...}
    //users和preference的键是一样的,键对应的值都是对象,键的数量也是一样的
    
    var result = _.map(users, function (value, key) {
        return _.extend({id: key}, prefereces[key]);
    });
    
    //[ { id: 'user-1', email: false },{ id: 'user-2', email: true },...]
    console.log(result);

    ■ 对象中键值包含值或函数,取出对象的所有键值对方到一个数组中,键值是函数的执行该函数

    var obj = {
        first: 'a',
        last: 'b',
        name: function () {
            return this.first + ' ' + this.last;
        },
        age: 22,
        retirement: 65,
        working: function () {
            return this.retirement - this.age;
        }
    };
    
    var result1 = _.map(obj, function (value, key) {
        var item = {};
        item[key] = _.isFunction(value) ? obj[key]() : value;
        return item;
    });
    
    //[ { first: 'a' },
    //    { last: 'b' },
    //    { name: 'a b' },
    //    { age: 22 },
    //    { retirement: 65 },
    //    { working: 43 } ]
    console.log(result1);
    
    //[ { first: 'a' },
    //    { last: 'b' },
    //    { name: 'a b' },
    //    { age: 22 },
    //    { retirement: 65 },
    //    { working: 43 } ]
    var result2=_.map(obj, function(value, key){
       var item={};
        item[key]= _.result(obj,key);
        return item;
    });
    
    console.log(result2);

    以上,一个是通过isFunction来判断键值是否是函数,一个直接调用result来执行键值函数。

    ■ 根据键取出一个对象中间对应的函数

    var object = {
        'user': 'fred',
        'greet': function(greeting, punctuation) {
            return greeting + ' ' + this.user + punctuation;
        }
    };
    
    var bound = _.bindKey(object, 'greet','hi');
    
    //hi fred!
    console.log(bound('!'));

    以上,bindKey,根据键greet这个键把它对应的函数取出来。

    ■ 把对象中的函数取出来放到一个数组中,再invoke它们

    var obj={
        firstName: 'a',
        lastName: 'b',
        first: function(){
            return this.firstName;
        },
        last: function(){
            return this.lastName;
        }
    };
    
    var methods =_.map(_.functions(obj),function(item){
        return [_.bindKey(obj, item)];
    });
    
    console.log(methods);
    
    //[ 'a', 'b' ]
    console.log(_.invoke(methods,0));

    ■ 把一个对象中的所有值取出来

    var _ = require('lodash');
    
    var obj = {
        first: 'a',
        last: 'b',
        age:50
    };
    
    var result = _.map(_.filter(_.values(obj), _.isString), function(item){
        return '<strong>' + item + '</strong>';
    });
    
    //[ '<strong>a</strong>', '<strong>b</strong>' ]
    console.log(result);

    不仅通过values把对象的值取出来,还用filter进行了排序,最后还把值包裹到html元素中。

    ■ 把对象的键值转换成数组元素,再放到更大的数组中去

    //把首字母转换成大写
    function capitalize(s){
        return s.charAt(0).toUpperCase() + s.slice(1);
    }
    
    //label接受对象的key
    //value接受对象的键值
    function format(label, value) {
        return '<label>' + capitalize(label) + ':</label>' +
            '<strong>' + value + '</strong>';
    }
    
    var object = {
        first: 'Julian',
        last: 'Ramos',
        age: 43
    };
    
    var tempParis =_.pairs(object);
    //[ [ 'first', 'Julian' ], [ 'last', 'Ramos' ], [ 'age', 43 ] ]
    console.log(tempParis);
    
    var result = _.map(tempParis, function(pair){
        return format.apply(undefined, pair);
    });

    以上,pairs方法把对象的键值作为数组的元素,比如[ 'first', 'Julian' ],再把[ 'first', 'Julian' ]放到一个更大的数组中:[ [ 'first', 'Julian' ], ...]


    ■ 对象的集合,计算某个字段的和,累加的初始值是数字

    var collection = [
        { ram: 1024, storage: 2048 },
        { ram: 2048, storage: 4096 },
        { ram: 1024, storage: 2048 },
        { ram: 2048, storage: 4096 }
    ];
    
    var result1 = _.reduce(collection, function(result, item){
        return result+item.ram;
    },0);
    //6144
    console.log(result1);
    
    var result2 = _.reduce(collection, function(result, item){
        return result+item.storage;
    },0);
    //12288
    console.log(result2);

    以上,0是累加的初始值。

    ■ 对象的集合,计算某个字段的和, 累加的初始值是对象,类加后的结果也是对象

    var collection = [
        {hits: 2, misses: 4},
        {hits: 5, misses: 1},
        {hits: 3, misses: 8},
        {hits: 7, misses: 3}
    ];
    
    var result = _.reduce(collection, function(result, item) {
        return {
            hits: result.hits + item.hits,
            misses: result.misses + item.misses
        };
    }, { hits: 0, misses: 0 });
    
    //{ hits: 17, misses: 16 }
    console.log(result);

    ■ 自定义累加的算法

    function add(a,b){
        return a+b;
    }
    
    var collection =[
        {wins:34, loses:21},
        {wins:58, loses:12},
        {wins:34, loses:23},
        {wins:40, loses:15},
    ];
    
    var result1 = _.reduce(_.range(1,6),add);//[ 1, 2, 3, 4, 5 ]
    console.log(result1);//15
    
    var result2 =_.reduce(_.pluck(collection,'wins'),add);
    console.log(result2);//166


    ■ 对象的集合,先过滤,然后自定义求和算法

    var collection = [
        { name: 'Gina', age: 34, enabled: true },
        { name: 'Trevor', age: 45, enabled: false },
        { name: 'Judy', age: 71, enabled: true },
        { name: 'Preston', age: 19, enabled: false }
    ];
    
    var result = _.reduce(_.filter(collection, 'enabled'), function(result, item){
        result.names.push(item.name);
        result.years+= item.age;
        return result;
    },{names:[], years:0});
    
    //{ names: [ 'Gina', 'Judy' ], years: 105 }
    console.log(result);


    ■ 对象的集合,自定义求和算法,并在算法中过滤

    var collection = [
        { name: 'Melissa', age: 28, enabled: true },
        { name: 'Kristy', age: 22, enabled: true },
        { name: 'Kerry', age: 31, enabled: false },
        { name: 'Damon', age: 36, enabled: false }
    ];
    
    var result = _.reduce(collection, function(result, item) {
        if (item.enabled) {
            result.names.push(item.name);
            result.years += item.age;
        }
        return result;
    }, { names: [], years: 0 });
    
    //{ names: [ 'Melissa', 'Kristy' ], years: 50 }
    console.log(result);


    ■ 对象集合,对象元素中有一个字段是整型数组,这些数组元素相加,把和最小所在的对象打印出来

    //对象中的一个字段是数值数组
    var collection = [
        { name: 'Madeline', scores: [ 88, 45, 83 ] },
        { name: 'Susan', scores: [ 79, 82, 78 ] },
        { name: 'Hugo', scores: [ 90, 84, 85 ] },
        { name: 'Thomas', scores: [ 74, 69, 78 ] }
    ];
    
    //对对象item的scores字段所代表的数组数组求和
    function score(item) {
        return _.reduce(item.scores, function(result, score) {
            return result + score;
        });
    }
    
    var result = _.min(collection, score);
    
    //{ name: 'Madeline', scores: [ 88, 45, 83 ] }
    console.log(result);

    如果求最大,那就是:

    var result = _.max(collection, score);

    ■ 对象的集合,对象元素中有个字段是整型号数组,求出每个对象元素整型数组的平均值,放在一个数组中,再求这个数组的平均值

    function average(items){
        return _.reduce(items, function(result, item){
            return result + item;
        }) / items.length;
    }
    
    var collection = [
        { name: 'Anthony', scores: [ 89, 59, 78 ] },
        { name: 'Wendy', scores: [ 84, 80, 81 ] },
        { name: 'Marie', scores: [ 58, 67, 63 ] },
        { name: 'Joshua', scores: [ 76, 68, 74 ] }
    ];
    
    //result表示累加之和
    //item表示集合中的元素
    //index表示集合元素索引
    //coll表示集合
    var result = _.reduce(collection, function(result, item, index, coll){
        var ave = average(item.scores);
        result.push(ave);
    
        //如果当前元素的索引是集合中的最后一个元素
        if(index === (coll.length - 1)){
            return average(result);
        }
        return result;
    },[]).toFixed(2);
    
    //73.08
    console.log(result);

    ■ 删除某个对象中的某些键值对

    var object = {
        first: 'a',
        last: 'b',
        age: 41
    },
    allowed = ['first','last'];
    
    var result = _.reduce(object,function(result, value, key){
        if(_.contains(allowed, key)){
            result[key] = value;
        }
        return result;
    },{});
    
    //{ first: 'a', last: 'b' }
    console.log(result);
    
    var result2 = _.pick(object, allowed);
    //{ first: 'a', last: 'b' }
    console.log(result2);

    以上,分别通过reduce和pick的方式把对象中的不需要的字段剔除了。


    ■ 剔除对象中不需要的键值对,并对某些键值进行转换

    var object = {
        first: '&lt;strong&gt;Nicole&lt;/strong&gt;',
        last: '&lt;strong&gt;Russel&lt;/strong&gt;',
        age: 26
    };
    
    
    var result = _.transform(object, function(result, value, key) {
        if (_.isString(value)) {
            result[key] = _.unescape(value);
        }
    });
    
    //{ first: '<strong>Nicole</strong>',
    //    last: '<strong>Russel</strong>' }
    console.log(result);

    以上,unescape是把键值转换成html元素。

    ■ 对对象的键值进行转换,再调用对象的原型方法

    function Person(first, last){
        this.first = first;
        this.last = last;
    }
    
    Person.prototype.name = function name(){
        return this.first + ' ' + this.last;
    }
    
    var darren = new Person('Darren','ji');
    
    var result = _.transform(darren, function(result, value,key){
       if(_.isString(value)){
           result[key] = value.toString();
       }
    }).name();
    
    //Darren ji
    console.log(result);

    ■ 对象集合,根据对象元素的某个字段进行分组

    var collection = [
        { id: _.uniqueId('id-'), position: 'absolute', top: 12 },
        { id: _.uniqueId('id-'), position: 'relative', top: 20 },
        { id: _.uniqueId('id-'), position: 'absolute', top: 12 },
        { id: _.uniqueId('id-'), position: 'relative', top: 20 }
    ];
    
    var result = _.groupBy(collection, 'position');
    
    //{ absolute:
    //    [ { id: 'id-1', position: 'absolute', top: 12 },
    //        { id: 'id-3', position: 'absolute', top: 12 } ],
    //        relative:
    //    [ { id: 'id-2', position: 'relative', top: 20 },
    //        { id: 'id-4', position: 'relative', top: 20 } ] }
    console.log(result);
    
    
    var result2 = _.indexBy(collection, 'id');
    
    //{ 'id-1': { id: 'id-1', position: 'absolute', top: 12 },
    //    'id-2': { id: 'id-2', position: 'relative', top: 20 },
    //    'id-3': { id: 'id-3', position: 'absolute', top: 12 },
    //    'id-4': { id: 'id-4', position: 'relative', top: 20 } }
    console.log(result2);

    ■ 为map方法绑定上下文

    var app = {
        states: [
            'running',
            'off',
            'paused'
        ],
        machines: [
            { id: _.uniqueId(), state: 1 },
            { id: _.uniqueId(), state: 0 },
            { id: _.uniqueId(), state: 0 },
            { id: _.uniqueId(), state: 2 }
        ]
    };
    
    var mapStates = _.partialRight(_.map, function(item){
        return _.extend({state: this.states[item.state]}, _.pick(item,'id'));
    },app);
    
    var result = mapStates(app.machines);
    
    //[ { state: 'off', id: '1' },
    //    { state: 'running', id: '2' },
    //    { state: 'running', id: '3' },
    //    { state: 'paused', id: '4' } ]
    console.log(result);

    以上,partialRight方法的第三个参数app是map方法的上下文。

    ■ 为reduce方法绑定上下文

    var collection = [ 12, 34, 53, 43 ],
        settings = { tax: 1.15 },
        applyTax = _.partialRight(_.reduce, function(result, item) {
            return result + item * this.tax;
        }, 0, settings);
    
    
    //163.30
    console.log(applyTax(collection).toFixed(2));

    ■ 对象集合,更改对象某个字段的值,类似泛型

    //this作为上下文对象有prop和value字段
    //this的prop键值决定哪个字段需要实施加法
    //item在这里会传入集合元素
    function add(item){
        var result = _.clone(item);
        result[this.prop] += this.value;
        return result;
    }
    
    function upper(item){
        var result = _.clone(item);
        result[this.prop]=result[this.prop].toUpperCase();
        return result;
    }
    
    var collection = [
        { name: 'Gerard', balance: 100 },
        { name: 'Jean', balance: 150 },
        { name: 'Suzanne', balance: 200 },
        { name: 'Darrell', balance: 250 }
    ];
    
    var mapAdd = _.partial(_.map, collection, add),
        mapUpper = _.partial(_.map, collection, upper);
    
    //[ { name: 'Gerard', balance: 150 },
    //    { name: 'Jean', balance: 200 },
    //    { name: 'Suzanne', balance: 250 },
    //    { name: 'Darrell', balance: 300 } ]
    console.log(mapAdd({ prop: 'balance', value: 50 }));
    
    
    //[ { name: 'GERARD', balance: 100 },
    //    { name: 'JEAN', balance: 150 },
    //    { name: 'SUZANNE', balance: 200 },
    //    { name: 'DARRELL', balance: 250 } ]
    console.log(mapUpper({ prop: 'name'}));


    ■ 对象集合,对某个字段求和,类似泛型

    function sum(a,b){
        return a+b[this.prop];
    }
    
    var collection = [
        { low: 40, high: 70 },
        { low: 43, high: 83 },
        { low: 39, high: 79 },
        { low: 45, high: 74 }
    ];
    
    var reduceSum = _.partial(_.reduce, collection, sum, 0);
    
    //167
    console.log(reduceSum({ prop: 'low' }));

    ■ 对象集合,先为对象元素增加一个字段,再对所有对象求和,求和自定义算法

    var collection = [
        { name: 'Wade', balance: 100 },
        { name: 'Donna', balance: 125 },
        { name: 'Glenn', balance: 90 },
        { name: 'Floyd', balance: 110 }
    ], bonus = 25;
    
    //为每个集合元素增加了一个bonus字段
    var mapped = _.map(collection, function(item) {
        return _.extend({
            bonus: item.balance + bonus
        }, item);
    });
    
    //求和
    //item是集合中的元素
    //index是集合中元素的索引
    //coll是集合
    //result是累计结果
    var result = _.reduce(mapped, function(result, item, index, coll) {
            result += (item.bonus - item.balance) / item.bonus;
    
            //如果累加到最后一个集合元素
            if (index === (coll.length - 1)) {
                result = result / coll.length * 100;
            }
            return result;
        }, 0).toFixed(2) + '%';
    
    //19.23%
    console.log(result);

    参考资料:lodash essentials

    未完待续~~

  • 相关阅读:
    理解Express express.static 和 __direname 及 __firename的含义
    HTTP请求中 request payload 和 formData 区别?
    POST提交数据之---Content-Type的理解;
    前端域名访问页面中的一些配置项
    使用Nginx来解决跨域的问题
    vue-resource get/post请求如何携带cookie的问题
    socket实现聊天功能(二)
    go语言之进阶篇通过结构体生成json
    go语言之进阶篇JSON处理
    go语言之进阶篇正则表达式
  • 原文地址:https://www.cnblogs.com/darrenji/p/5011448.html
Copyright © 2020-2023  润新知