Mapa sobre claves de preservación de objetos


129

La mapfunción en underscore.js, si se llama con un objeto javascript, devuelve una matriz de valores asignados a partir de los valores del objeto.

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

¿hay alguna manera de hacer que conserve las llaves? es decir, quiero una función que devuelva

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

Si usted, como yo, vino aquí buscando una función similar a 'mapValues' que cambie el objeto real en lugar de devolver uno nuevo, consulte esta solución simple: stackoverflow.com/questions/30894044/…
Michael Trouw

Respuestas:


228

Con subrayado

El subrayado proporciona una función _.mapObjectpara asignar los valores y preservar las claves.

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

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

DEMO


Con lodash

Lodash proporciona una función _.mapValuespara asignar los valores y preservar las claves.

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

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

DEMO


Se han realizado esfuerzos para poner una función _.mapValues ​​en subrayado: Problema relevante , Solicitud de extracción para _.mapValues . Espero que esto pase :)
raffomania

me parece que estás convirtiendo un OBJETO en un objeto, ¿o estoy loco?
jsh

@jsh En este caso, _.map()está regresando [['one', 3], ['two', 6], ['three', 9]], que es una matriz de matrices, y lo _.object()está volviendo a convertir en un objeto.
Jezen Thomas

56

Logré encontrar la función requerida en lodash, una biblioteca de utilidades similar al guión bajo.

http://lodash.com/docs#mapValues

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

Crea un objeto con las mismas claves que el objeto y los valores generados al ejecutar cada propiedad enumerable del objeto a través de la devolución de llamada. La devolución de llamada está vinculada a thisArg y se invoca con tres argumentos; (valor, clave, objeto).


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

Sé que esto es antiguo, pero ahora Underscore tiene un nuevo mapa para objetos:

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

Por supuesto, puede crear un mapa flexible para matrices y objetos.

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

55
Nota para los usuarios de lodash: jdalton ha decidido romper la compatibilidad con underscore.js por este cambio. lodash no apoyará mapObject; mira el mapValuesmétodo de lodash en su lugar.
Mark Amery

13

¿Qué tal esta versión en JS simple ( ES6 / ES2015 )?

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

jsbin

Si desea mapear sobre un objeto de forma recursiva (mapear obj anidado), puede hacerlo así:

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

Desde ES7 / ES2016 puede usar en Object.entrieslugar de Object.keysesto:

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

5

Sé que ha pasado mucho tiempo, pero aún falta la solución más obvia a través de fold (también conocido como reducir en js), por razones de integridad lo dejaré aquí:

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

Estoy de acuerdo con el uso de la biblioteca Lodash, pero los programadores están usando este tipo de bibliotecas y no saben cómo se puede lograr esto en Vanilla JS. ¡Entonces, agradezco tu respuesta!
cyonder

3

_.map devuelve una matriz, no un objeto.

Si quieres un objeto, es mejor que uses una función diferente, como each; si realmente quieres usar el mapa, puedes hacer algo como esto:

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

pero eso es confuso, al ver mapuno esperaría tener una matriz como resultado y luego hacer algo con ella.


Al leer los documentos, tuve la sensación de que no sería natural probar esto en underscore.js. Creo que mi caso de uso es bastante natural, ¿por qué no lo admiten?
xuanji

Probablemente, una razón podría ser que mapse usa para cambiar una entrada que produce una matriz como salida, podría componer _.objecty _.mapcomo @GG. escribió, pero eso es cuestión de gustos en este momento.
Alberto Zaccagni

3

Creo que quieres un mapa función (para asignar una función sobre los valores de un objeto), que es lo suficientemente fácil de implementar usted mismo:

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

2
const mapObject = (obj = {}, mapper) =>
  Object.entries(obj).reduce(
    (acc, [key, val]) => ({ ...acc, [key]: mapper(val) }),
    {},
  );

Estaba a punto de agregar esta respuesta yo mismo. ¡Me alegro de haberme desplazado!
Bill Criswell

0

Una solución mixta para el error de mapa de subrayado : 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;
    }
}); 

Una solución simple que mantiene la clave correcta y devuelve como objeto Todavía se usa de la misma manera que i guest, podría usar esta función para anular la función _.map con errores

o simplemente como lo usé como mezcla

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.