【问题标题】:Map over object preserving keys映射对象保留键
【发布时间】:2013-09-26 08:35:02
【问题描述】:

underscore.js 中的map 函数,如果使用 javascript 对象调用,则返回从对象值映射的值数组。

_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; });
=> [3, 6, 9]

有没有办法让它保留密钥?即,我想要一个返回的函数

{one: 3, two: 6, three: 9}

【问题讨论】:

  • 如果你和我一样,来这里寻找一个类似“mapValues”的函数来改变实际对象而不是返回一个新对象,看看这个简单的解决方案:stackoverflow.com/questions/30894044/…

标签: javascript underscore.js lodash


【解决方案1】:

下划线

Underscore 提供了一个函数_.mapObject 来映射值并保留键。

_.mapObject({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; });

// => { one: 3, two: 6, three: 9 }

DEMO


使用 Lodash

Lodash 提供了一个函数_.mapValues 来映射值并保留键。

_.mapValues({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; });

// => { one: 3, two: 6, three: 9 }

DEMO

【讨论】:

  • 已经努力将 _.mapValues 函数放入下划线:Relevant IssuePull Request for _.mapValues。我希望这能通过:)
  • 在我看来你是在把一个 OBJECT 变成一个对象,还是我疯了?
  • @jssh 在这种情况下,_.map() 正在返回 [['one', 3], ['two', 6], ['three', 9]],这是一个数组的数组,_.object() 正在将其转回一个对象。
【解决方案2】:

我设法在 lodash 中找到了所需的函数,lodash 是一个类似于下划线的实用程序库。

http://lodash.com/docs#mapValues

_.mapValues(object, [callback=identity], [thisArg])

创建一个对象,其键值与生成的对象和值相同 通过回调运行对象的每个自己的可枚举属性。 回调绑定到 thisArg 并使用三个参数调用; (值、键、对象)。

【讨论】:

    【解决方案3】:

    var mapped = _.reduce({ one: 1, two: 2, three: 3 }, function(obj, val, key) {
        obj[key] = val*3;
        return obj;
    }, {});
    
    console.log(mapped);
    <script src="http://underscorejs.org/underscore-min.js"></script>
    <script src="https://getfirebug.com/firebug-lite-debug.js"></script>

    【讨论】:

      【解决方案4】:

      这个版本的纯 JS (ES6 / ES2015)怎么样?

      let newObj = Object.assign(...Object.keys(obj).map(k => ({[k]: obj[k] * 3})));
      

      jsbin

      如果你想递归地映射一个对象(映射嵌套的obj),可以这样做:

      const mapObjRecursive = (obj) => {
        Object.keys(obj).forEach(key => {
          if (typeof obj[key] === 'object') obj[key] = mapObjRecursive(obj[key]);
          else obj[key] = obj[key] * 3;
        });
        return obj;
      };
      

      jsbin

      ES7 / ES2016 开始,您可以像这样使用 Object.entries 而不是 Object.keys

      let newObj = Object.assign(...Object.entries(obj).map(([k, v]) => ({[k]: v * 3})));
      

      ES2019 开始,您可以使用Object.fromEntries

      let newObj = Object.fromEntries(Object.entries(obj).map(([k, v]) => ([k, v * 3])))
      

      【讨论】:

        【解决方案5】:

        我知道这是旧的,但现在下划线有一个新的对象地图:

        _.mapObject(object, iteratee, [context]) 
        

        您当然可以为数组和对象构建灵活的映射

        _.fmap = function(arrayOrObject, fn, context){
            if(this.isArray(arrayOrObject))
              return _.map(arrayOrObject, fn, context);
            else
              return _.mapObject(arrayOrObject, fn, context);
        }
        

        【讨论】:

        【解决方案6】:

        我知道这已经很长时间了,但仍然缺少最明显的折叠解决方案(在 js 中也称为 reduce),为了完整起见,我将把它留在这里:

        function mapO(f, o) {
          return Object.keys(o).reduce((acc, key) => {
            acc[key] = f(o[key])
            return acc
          }, {})
        }
        

        【讨论】:

        • 我可以使用 Lodash 库,但程序员正在使用这类库,不知道如何在 vanilla JS 中实现这些。所以,我很感激你的回答!
        【解决方案7】:

        _.map 返回一个数组,而不是一个对象。

        如果你想要一个对象,你最好使用不同的函数,比如each;如果你真的想使用地图,你可以这样做:

        Object.keys(object).map(function(value, index) {
           object[value] *= 3;
        })
        

        但这很令人困惑,当看到 map 时,人们会期望得到一个数组作为结果,然后用它做点什么。

        【讨论】:

        • 我在阅读文档时有一种感觉,在 underscore.js 中尝试这个是不自然的。我觉得我的用例很自然,他们为什么不支持呢?
        • 一个原因可能是map 用于更改输入以生成数组作为输出,您可以将_.object_.map 组合为@GG。写的,但在这一点上这是一个品味问题。
        【解决方案8】:

        我认为您想要一个 mapValues 函数(将函数映射到对象的值),这很容易自己实现:

        mapValues = function(obj, f) {
          var k, result, v;
          result = {};
          for (k in obj) {
            v = obj[k];
            result[k] = f(v);
          }
          return result;
        };
        

        【讨论】:

          【解决方案9】:
          const mapObject = (obj = {}, mapper) =>
            Object.entries(obj).reduce(
              (acc, [key, val]) => ({ ...acc, [key]: mapper(val) }),
              {},
            );
          

          【讨论】:

          • 我正要自己添加这个答案。很高兴我滚动了!
          【解决方案10】:

          混合修复下划线地图错误:P

          _.mixin({ 
              mapobj : function( obj, iteratee, context ) {
                  if (obj == null) return [];
                  iteratee = _.iteratee(iteratee, context);
                  var keys = obj.length !== +obj.length && _.keys(obj),
                      length = (keys || obj).length,
                      results = {},
                      currentKey;
                  for (var index = 0; index < length; index++) {
                    currentKey = keys ? keys[index] : index;
                    results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
                  }
                  if ( _.isObject( obj ) ) {
                      return _.object( results ) ;
                  } 
                  return results;
              }
          }); 
          

          一个简单的解决方法,保留正确的键并作为对象返回 它的使用方式仍然与我的客人相同,您可以使用此功能 覆盖错误的 _.map 函数

          或者就像我用它作为一个mixin一样

          _.mapobj ( options , function( val, key, list ) 
          

          【讨论】:

            【解决方案11】:

            您可以在 Lodash 中使用 _.mapValues(users, function(o) { return o.age; });,在下划线中使用 _.mapObject({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; });

            在此处查看交叉文档:http://jonathanpchen.com/underdash-api/#mapvalues-object-iteratee-identity

            【讨论】:

              【解决方案12】:

              _.map 使用 lodash 之类的循环来实现这一点

               var result={};
              _.map({one: 1, two: 2, three: 3}, function(num, key){ result[key]=num * 3; });
              console.log(result)
              
              //output
              {one: 1, two: 2, three: 3}
              

              Reduce 看起来很聪明,就像上面的答案

              _.reduce({one: 1, two: 2, three: 3}, function(result, num, key) {
                result[key]=num * 3
                return result;
              }, {});
              
              //output
              {one: 1, two: 2, three: 3}
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2018-05-06
                • 1970-01-01
                • 1970-01-01
                • 2011-12-31
                • 1970-01-01
                • 1970-01-01
                • 2022-07-29
                相关资源
                最近更新 更多