Mapuj klucze zachowujące obiekty


130

mapFunkcja w underscore.js, jeśli wywołana z obiektu JavaScript, zwraca tablicę wartości odwzorowanych od wartości obiektu.

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

czy jest sposób, aby zachować klucze? tj. chcę funkcję, która zwraca

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

Jeśli tak jak ja przyszedłeś tutaj, szukając funkcji podobnej do mapValues, która zmienia rzeczywisty obiekt zamiast zwracać nowy, sprawdź to proste rozwiązanie: stackoverflow.com/questions/30894044/ ...
Michael Trouw

Odpowiedzi:


229

Z podkreśleniem

Podkreślenie zapewnia funkcję _.mapObjectmapowania wartości i zachowania kluczy.

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

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

DEMO


Z Lodash

Lodash udostępnia funkcję _.mapValuesmapowania wartości i zachowywania kluczy.

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

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

DEMO


Podjęto próby umieszczenia funkcji _.mapValues ​​w podkreśleniu: Relevant Issue , Pull Request for _.mapValues . Mam nadzieję, że to się uda :)
raffomania

wydaje mi się, że robisz przedmiot w przedmiot, czy też oszalałem?
jsh

@jsh W tym przypadku _.map()zwraca [['one', 3], ['two', 6], ['three', 9]], czyli tablicę tablic, i _.object()zamienia ją z powrotem w obiekt.
Jezen Thomas,

56

Udało mi się znaleźć wymaganą funkcję w lodash, bibliotece narzędziowej podobnej do podkreślenia.

http://lodash.com/docs#mapValues

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

Tworzy obiekt z tymi samymi kluczami, co obiekt i wartości generowane przez uruchomienie każdej własnej wyliczalnej właściwości obiektu za pośrednictwem wywołania zwrotnego. Callback jest powiązany z thisArg i wywoływany z trzema argumentami; (wartość, klucz, obiekt).


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

Wiem, że to jest stare, ale teraz Underscore ma nową mapę obiektów:

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

Możesz oczywiście zbudować elastyczną mapę zarówno dla tablic, jak i obiektów

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

5
Uwaga dla użytkowników lodash: jdalton zdecydował się zerwać zgodność z underscore.js w związku z tą zmianą. lodash nie będzie wspierać mapObject; mapValueszamiast tego spójrz na metodę lodash .
Mark Amery

13

A co z tą wersją w zwykłym JS ( ES6 / ES2015 )?

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

jsbin

Jeśli chcesz mapować obiekt rekurencyjnie (map nested obj), możesz to zrobić w następujący sposób:

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

Od ES7 / ES2016 możesz użyć Object.entrieszamiast Object.keystego:

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

5

Wiem, że minęło dużo czasu, ale nadal brakuje najbardziej oczywistego rozwiązania poprzez spasowanie (czyli zmniejszenie w js), ze względu na kompletność zostawię to tutaj:

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

Nie przeszkadza mi korzystanie z biblioteki Lodash, ale programiści używają tego rodzaju bibliotek i nie wiedzą, jak można to osiągnąć w waniliowym JS. Doceniam twoją odpowiedź!
cyonder

3

_.map zwraca tablicę, a nie obiekt.

Jeśli chcesz mieć obiekt, lepiej użyj innej funkcji, na przykład each; jeśli naprawdę chcesz używać mapy, możesz zrobić coś takiego:

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

ale to jest mylące, gdy mapktoś spodziewałby się mieć tablicę jako wynik, a potem coś z nią zrobić.


Miałem przeczucie, że czytając dokumenty, że nie byłoby naturalne wypróbowanie tego w underscore.js. Myślę, że mój przypadek użycia jest całkiem naturalny, dlaczego go nie obsługują?
xuanji

Jednym z powodów może być mapto, że jest używany do zmiany danych wejściowych, tworząc tablicę jako dane wyjściowe, możesz komponować _.objecti _.mapjako @GG. napisał, ale to kwestia gustu w tym momencie.
Alberto Zaccagni

3

Myślę, że potrzebujesz funkcji mapValues (do mapowania funkcji na wartości obiektu), która jest dość łatwa do zaimplementowania samodzielnie:

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) }),
    {},
  );

Właśnie miałem dodać tę odpowiedź. Cieszę się, że przewinęłam!
Bill Criswell

0

Naprawiono miksowanie błędu mapy z podkreśleniem : 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;
    }
}); 

Proste obejście, które zachowuje właściwy klawisz i zwraca go jako obiekt Nadal jest używane tak samo jak i guest Możesz użyć tej funkcji do nadpisania błędnej funkcji _.map

lub po prostu tak, jak użyłem go jako miksu

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


0

_.map używając do tego pętli lodash like

 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 is sprytny wygląda jak powyżej answare

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

//output
{one: 1, two: 2, three: 3}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.