Карта поверх ключей сохранения объекта

129

mapФункция underscore.js, если вызывается с объектом яваскрипта, возвращает массив значений , отображенных из значений объекта.

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

есть ли способ заставить его сохранить ключи? т.е. мне нужна функция, которая возвращает

{one: 3, two: 6, three: 9}
xuanji
источник
Если вы, как и я, пришли сюда в поисках функции типа mapValues, которая изменяет фактический объект вместо того, чтобы возвращать новый, проверьте это простое решение: stackoverflow.com/questions/30894044/…
Майкл Трау

Ответы:

228

С подчеркиванием

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

GG.
источник
Были попытки поместить функцию _.mapValues ​​в подчеркивание: соответствующая проблема , запрос на извлечение для _.mapValues . Надеюсь, это пройдет :)
raffomania
мне кажется, что вы превращаете ОБЪЕКТ в объект, или я сошел с ума?
jsh
@jsh В этом случае _.map()возвращается [['one', 3], ['two', 6], ['three', 9]], который представляет собой массив массивов, и _.object()превращает его обратно в объект.
Jezen Thomas
56

Мне удалось найти нужную функцию в lodash, служебной библиотеке, похожей на подчеркивание.

http://lodash.com/docs#mapValues

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

Создает объект с теми же ключами, что и у объекта, и значениями, сгенерированными путем запуска каждого собственного перечислимого свойства объекта через обратный вызов. Обратный вызов привязан к thisArg и вызывается с тремя аргументами; (значение, ключ, объект).

xuanji
источник
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>

kunalgolani
источник
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);
}
Rayjax
источник
5
Примечание для пользователей lodash: jdalton решил нарушить совместимость с underscore.js из- за этого изменения. lodash не поддерживает mapObject; mapValuesвместо этого посмотрите на метод lodash .
Марк Эмери
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})));
Rotareti
источник
5

Я знаю, что это было давно, но все еще отсутствует наиболее очевидное решение через fold (также известное как сокращение в js), для полноты картины я оставлю его здесь:

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
Одна из причин, вероятно, может заключаться в том, что 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;
};
joyrexus
источник
2
const mapObject = (obj = {}, mapper) =>
  Object.entries(obj).reduce(
    (acc, [key, val]) => ({ ...acc, [key]: mapper(val) }),
    {},
  );
Найджел Кирби
источник
Я собирался сам добавить этот ответ. Рад, что пролистал!
Билл Крисуэлл,
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;
    }
}); 

Простой обходной путь, который сохраняет правильную клавишу и возвращает как объект. Он по-прежнему используется так же, как и я, гость, вы можете использовать эту функцию для переопределения функции bugy _.map.

или просто, как я использовал его как миксин

_.mapobj ( options , function( val, key, list ) 
паскаль
источник