Peta di atas kunci pengawet objek

129

The mapfungsi dalam underscore.js, jika disebut dengan benda javascript, mengembalikan sebuah array nilai dipetakan dari nilai-nilai objek.

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

apakah ada cara untuk membuatnya melestarikan kunci? yaitu, saya ingin fungsi yang mengembalikan

{one: 3, two: 6, three: 9}
xuanji
sumber
Jika Anda, seperti saya, datang ke sini untuk mencari fungsi seperti 'mapValues' yang mengubah objek aktual alih-alih mengembalikan yang baru, periksa solusi sederhana ini: stackoverflow.com/questions/30894044/…
Michael Trouw

Jawaban:

228

Dengan Garis Bawah

Underscore menyediakan fungsi _.mapObjectuntuk memetakan nilai dan mempertahankan kunci.

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

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

DEMO


Dengan Lodash

Lodash menyediakan fungsi _.mapValuesuntuk memetakan nilai dan mempertahankan kunci.

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

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

DEMO

GG.
sumber
Ada upaya untuk mendapatkan fungsi _.mapValues ​​menjadi garis bawah: Masalah yang Relevan , Tarik Permintaan untuk _.mapValues . Saya harap ini melewati :)
raffomania
Sepertinya saya membuat OBJECT menjadi objek, atau apakah saya keluar dari pikiran saya?
jsh
@ jsh Dalam hal ini, _.map()kembali [['one', 3], ['two', 6], ['three', 9]], yang merupakan array array, dan _.object()mengubahnya kembali menjadi objek.
Jezen Thomas
56

Saya berhasil menemukan fungsi yang diperlukan di lodash, sebuah perpustakaan utilitas yang mirip dengan garis bawah.

http://lodash.com/docs#mapValues

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

Membuat objek dengan kunci yang sama dengan objek dan nilai-nilai yang dihasilkan dengan menjalankan masing-masing properti enumerable objek melalui callback. Callback terikat dengan thisArg dan dipanggil dengan tiga argumen; (nilai, kunci, objek).

xuanji
sumber
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
sumber
13

Saya tahu ini sudah tua, tetapi sekarang Underscore memiliki peta baru untuk objek:

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

Tentu saja Anda dapat membuat peta yang fleksibel untuk array dan objek

_.fmap = function(arrayOrObject, fn, context){
    if(this.isArray(arrayOrObject))
      return _.map(arrayOrObject, fn, context);
    else
      return _.mapObject(arrayOrObject, fn, context);
}
Rayjax
sumber
5
Catatan untuk pengguna lodash: jdalton telah memutuskan untuk memutus kompatibilitas dengan underscore.js atas perubahan ini. lodash tidak akan mendukung mapObject; lihat mapValuesmetode lodash sebagai gantinya.
Mark Amery
13

Bagaimana dengan versi ini di JS polos ( ES6 / ES2015 )?

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

jsbin

Jika Anda ingin memetakan objek secara rekursif (map nested obj), bisa dilakukan seperti ini:

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

Karena ES7 / ES2016 Anda dapat menggunakan Object.entriesdaripada Object.keysseperti ini:

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

Saya tahu ini sudah lama, tetapi masih solusi yang paling jelas melalui flip (alias mengurangi js) hilang, demi kelengkapan saya akan meninggalkannya di sini:

function mapO(f, o) {
  return Object.keys(o).reduce((acc, key) => {
    acc[key] = f(o[key])
    return acc
  }, {})
}
Darwin
sumber
Saya setuju dengan penggunaan perpustakaan Lodash tetapi programmer menggunakan perpustakaan semacam ini, dan tidak tahu bagaimana hal-hal ini dapat dicapai di vanilla JS. Jadi, saya menghargai jawaban Anda!
cyonder
3

_.map mengembalikan Array, bukan Object.

Jika Anda menginginkan objek Anda lebih baik menggunakan fungsi yang berbeda, seperti each; jika Anda benar-benar ingin menggunakan peta, Anda bisa melakukan sesuatu seperti ini:

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

tapi itu membingungkan, ketika melihat mapseseorang akan mengharapkan untuk memiliki array sebagai hasilnya dan kemudian membuat sesuatu dengannya.

Alberto Zaccagni
sumber
Saya merasa membaca dokumen bahwa tidak alami untuk mencoba ini di bawah. Js. Saya pikir use case saya cukup alami, mengapa mereka tidak mendukungnya?
xuanji
Salah satu alasan mungkin yang mapdigunakan untuk mengubah input yang menghasilkan array sebagai output, Anda dapat menulis _.objectdan _.mapsebagai @GG. menulis, tapi itu masalah selera pada saat ini.
Alberto Zaccagni
3

Saya pikir Anda ingin fungsi mapValues (untuk memetakan fungsi atas nilai-nilai objek), yang cukup mudah untuk diterapkan sendiri:

mapValues = function(obj, f) {
  var k, result, v;
  result = {};
  for (k in obj) {
    v = obj[k];
    result[k] = f(v);
  }
  return result;
};
joyrexus
sumber
2
const mapObject = (obj = {}, mapper) =>
  Object.entries(obj).reduce(
    (acc, [key, val]) => ({ ...acc, [key]: mapper(val) }),
    {},
  );
Nigel Kirby
sumber
Saya akan menambahkan jawaban ini sendiri. Senang saya menggulir!
Bill Criswell
0

Perbaikan campuran untuk bug peta garis bawah : 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;
    }
}); 

Solusi sederhana yang menjaga kunci kanan dan kembali sebagai objek. Masih digunakan dengan cara yang sama seperti tamu saya, Anda bisa menggunakan fungsi ini untuk mengganti fungsi _.map yang bermasalah.

atau sama seperti saya menggunakannya sebagai mixin

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