映射对象保留键


129

mapunderscore.js中的函数(如果与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/...
迈克尔忠诚报

Answers:


228

下划线

下划线提供了_.mapObject映射值和保留键的功能。

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

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

DEMO


洛达什

Lodash提供了_.mapValues映射值和保留键的功能。

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

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

DEMO


已经有一些努力使_.mapValues函数成为下划线:相关问题_ . mapValues的请求。我希望这会通过:)
拉夫马尼亚州

在我看来,您好像正在将对象变成对象,还是我不在意?
jsh

@jsh在这种情况下,_.map()returning [['one', 3], ['two', 6], ['three', 9]],它是一个数组数组,并将_.object()其变成对象。
Jezen Thomas 2015年

56

我设法在lodash(类似于下划线的实用程序库)中找到了所需的功能。

http://lodash.com/docs#mapValues

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

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


19

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>


13

我知道这很旧,但是现在Underscore有了一个新的对象映射:

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

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

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

5
提醒lodash用户:jdalton已决定通过此更改破坏与underscore.js的兼容性。lodash不支持mapObject; 改用lodash的mapValues方法。
Mark Amery 2015年

13

普通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})));

5

我知道已经很长时间了,但是仍然缺少通过fold(在js中为reduce)的最明显的解决方案,出于完整性考虑,我将其保留在这里:

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

我对Lodash库的使用还可以,但是程序员正在使用这类库,却不知道在香草JS中如何实现。因此,感谢您的回答!
cyonder

3

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

如果您想要一个对象,最好使用其他函数,例如each; 如果您真的想使用地图,可以执行以下操作:

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

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


我有一种阅读文档的感觉,那就是在underscore.js中尝试这样做是不自然的。我认为我的用例很自然,为什么他们不支持呢?
xuanji 2013年

一个原因可能有可能是map用于改变产生阵列作为输出的输入,则可以构成_.object_.map作为@GG。写道,但是这只是一个品味问题。
阿尔贝托·扎卡尼

3

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

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


0

下划线地图错误的混合修复: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函数

或仅仅是因为我将其用作混音

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.