multidimensional - javascript mehrdimensionales array




Kartenfunktion für Objekte(anstelle von Arrays) (15)

Ich habe ein Objekt:

myObject = { 'a': 1, 'b': 2, 'c': 3 }

Ich suche nach einer nativen Methode, ähnlich wie Array.prototype.map , die wie folgt verwendet wird:

newObject = myObject.map(function (value, label) {
    return value * value;
});

// newObject is now { 'a': 1, 'b': 4, 'c': 9 }

Hat JavaScript eine solche map für Objekte? (Ich möchte dies für Node.JS, also interessieren mich nicht Cross-Browser-Probleme.)


Basierend auf @ Amberlamps Antwort, hier ist eine Dienstprogrammfunktion (als Kommentar sah es hässlich aus)

function mapObject(obj, mapFunc){
    return Object.keys(obj).reduce(function(newObj, value) {
        newObj[value] = mapFunc(obj[value]);
        return newObj;
    }, {});
}

und die Verwendung ist:

var obj = {a:1, b:3, c:5}
function double(x){return x * 2}

var newObj = mapObject(obj, double);
//=>  {a: 2, b: 6, c: 10}

Das ist gerade bs, und jeder in der JS-Community weiß es. Es sollte diese Funktionalität geben:

const obj1 = {a:4, b:7};
const obj2 = Object.map(obj1, (k,v) => v + 5);

console.log(obj1); // {a:4, b:7}
console.log(obj2); // {a:9, b:12}

hier ist die naive Umsetzung:

Object.map = function(obj, fn, ctx){

    const ret = {};

    Object.keys(obj).forEach(function(k){
        ret[k] = fn.call(ctx || null, k, obj[k]);
    });

    return ret;
};

es ist super nervig das man es sich selbst ständig einspielen muss;)

Wenn Sie etwas anspruchsvolleres möchten, das die Object-Klasse nicht beeinträchtigt, versuchen Sie Folgendes:

let map = function (obj, fn, ctx) {
  return Object.keys(obj).reduce((a, b) => {
    a[b] = fn.call(ctx || null, b, obj[b]);
    return a;
  }, {});
};


const x = map({a: 2, b: 4}, (k,v) => {
    return v*2;
});

Aber es ist sicher, diese Map-Funktion zu Object hinzuzufügen, nur nicht zu Object.prototype hinzuzufügen.

Object.map = ... // fairly safe
Object.prototype.map ... // not ok

Die map () ändert das ursprüngliche Array nicht.

Es erstellt ein neues Array mit den Ergebnissen des Aufrufs einer Funktion für jedes Array-Element.

array.map(function(currentValue, index, arr), thisValue)


currentValue : Required. The value of the current element 
index : Optional. The array index of the current element 
arr : Optional. The array object the current element belongs to

Beispiel:

var numbers = [65, 44, 12, 4];

function multiplyArrayElement(num) {
    return num * document.getElementById("multiplyWith").value;
}

function myFunction() {
    document.getElementById("demo").innerHTML = numbers.map(multiplyArrayElement);
}

Unterstützte Browser: Chrome Ja IE 9.0 Firefox 1.5 Safari Ja Opera Ja


Die akzeptierte Antwort hat zwei Nachteile:

  • Es verwendet Array.prototype.reduce , weil das Reduzieren bedeutet, die Struktur eines zusammengesetzten Typs zu ändern, was in diesem Fall nicht geschieht.
  • Es ist nicht besonders wiederverwendbar

Ein ES6 / ES2015-Funktionsansatz

Bitte beachten Sie, dass alle Funktionen in Curry-Form definiert sind.

// small, reusable auxiliary functions

const keys = o => Object.keys(o);

const assign = (...o) => Object.assign({}, ...o);

const map = f => xs => xs.map(x => f(x));

const mul = y => x => x * y;

const sqr = x => mul(x) (x);


// the actual map function

const omap = f => o => {
  o = assign(o); // A
  map(x => o[x] = f(o[x])) (keys(o)); // B
  return o;
};


// mock data

const o = {"a":1, "b":2, "c":3};


// and run

console.log(omap(sqr) (o));
console.log(omap(mul(10)) (o));

  • In Zeile A wird o neu zugewiesen. Da Javascript Referenzwerte durch Freigabe übergibt, wird eine flache Kopie von o generiert. Wir sind nun in der Lage, innerhalb von omap zu mutieren, ohne im übergeordneten Bereich zu mutieren.
  • In Zeile B map der Rückgabewert der map ignoriert, da map eine Mutation von o ausführt. Da dieser Nebeneffekt innerhalb von omap bleibt und im übergeordneten Bereich nicht sichtbar ist, ist er völlig akzeptabel.

Dies ist nicht die schnellste Lösung, sondern eine deklarative und wiederverwendbare Lösung. Hier ist die gleiche Implementierung wie eine Einzeiler, knapp aber weniger lesbar:

const omap = f => o => (o = assign(o), map(x => o[x] = f(o[x])) (keys(o)), o);

Anhang - Warum sind Objekte nicht standardmäßig iterierbar?

ES2015 spezifizierte den Iterator und die iterierbaren Protokolle. Objekte sind jedoch immer noch nicht iterierbar und somit nicht abbildbar. Der Grund ist die Mischung von Daten und Programmlevel .


Es gibt keine native map für das Object Objekt, aber wie wäre es damit:

Object.keys(myObject).map(function(key, index) {
   myObject[key] *= 2;
});

console.log(myObject);

// => { 'a': 2, 'b': 4, 'c': 6 }

Aber Sie könnten leicht über ein Objekt iterieren, indem Sie for ... in :

for(var key in myObject) {
    if(myObject.hasOwnProperty(key)) {
        myObject[key] *= 2;
    }
}

Aktualisieren

Viele Leute erwähnen, dass die vorherigen Methoden kein neues Objekt zurückgeben, sondern auf dem Objekt selbst operieren. Zu diesem Zweck wollte ich eine andere Lösung hinzufügen, die ein neues Objekt zurückgibt und das ursprüngliche Objekt unverändert lässt:

var newObject = Object.keys(myObject).reduce(function(previous, current) {
    previous[current] = myObject[current] * myObject[current];
    return previous;
}, {});

console.log(newObject);
// => { 'a': 1, 'b': 4, 'c': 9 }

console.log(myObject);
// => { 'a': 1, 'b': 2, 'c': 3 }

Array.prototype.reduce reduziert ein Array auf einen einzelnen Wert, indem der vorherige Wert mit dem aktuellen Wert zusammengeführt wird. Die Kette wird durch ein leeres Objekt {} initialisiert. Bei jeder Iteration wird ein neuer Schlüssel von myObject mit seinem Quadrat als Wert hinzugefügt.


Es ist ziemlich einfach, eins zu schreiben:

Object.map = function(o, f, ctx) {
    ctx = ctx || this;
    var result = {};
    Object.keys(o).forEach(function(k) {
        result[k] = f.call(ctx, o[k], k, o); 
    });
    return result;
}

mit Beispielcode:

> o = { a: 1, b: 2, c: 3 };
> r = Object.map(o, function(v, k, o) {
     return v * v;
  });
> r
{ a : 1, b: 4, c: 9 }

Hinweis: In dieser Version können Sie (wie in der Array Methode) auch this Kontext für den Rückruf festlegen.

BEARBEITEN - geändert, um die Verwendung von Object.prototype zu entfernen, um sicherzustellen, dass es nicht mit einer vorhandenen Eigenschaft namens map auf dem Objekt kollidiert.


Hey, schrieb eine kleine Mapper-Funktion, die helfen könnte.

    function propertyMapper(object, src){
         for (var property in object) {   
           for (var sourceProp in src) {
               if(property === sourceProp){
                 if(Object.prototype.toString.call( property ) === '[object Array]'){
                   propertyMapper(object[property], src[sourceProp]);
                   }else{
                   object[property] = src[sourceProp];
                }
              }
            }
         }
      }

Ich bin hierher gekommen, um nach einem Objekt zu suchen und es zu beantworten, um es einem Array zuzuordnen, und habe diese Seite als Ergebnis erhalten. Falls Sie hierher gekommen sind, um nach der gleichen Antwort wie ich zu suchen, können Sie wie folgt ein Array zuordnen.

Sie können map verwenden, um ein neues Array wie folgt vom Objekt zurückzugeben:

var newObject = Object.keys(myObject).map(function(key) {
   return myObject[key];
});

Ich stieß auf diese als ein erstes Element in einer Google-Suche versucht zu lernen, dies zu tun, und dachte, ich würde für andere folsk finden diese kürzlich die Lösung, die ich gefunden, die das npm-Paket unveränderlich verwendet.

Ich denke, es ist interessant zu teilen, weil unveränderlich die EXAKT-Situation des OP in ihrer eigenen Dokumentation verwendet - das Folgende ist nicht mein eigener Code, sondern stammt aus der aktuellen immutable-js-Dokumentation:

const { Seq } = require('immutable')
const myObject = { a: 1, b: 2, c: 3 }
Seq(myObject).map(x => x * x).toObject();
// { a: 1, b: 4, c: 9 } 

Nicht, dass Seq andere Eigenschaften hat ("Seq" beschreibt eine "Lazy" -Operation, die es ermöglicht, alle übergeordneten Auflistungsmethoden (wie map und filter) effizient zu ketten, indem keine Zwischensammlungen erstellt werden) und einige andere unveränderliche js-Daten Strukturen könnten auch die Arbeit sehr effizient erledigen.

Jeder, der diese Methode verwendet, muss natürlich npm install immutable und möchte die Dokumente lesen:

https://facebook.github.io/immutable-js/


Ich wollte speziell die gleiche Funktion verwenden, die ich für Arrays für ein einzelnes Objekt verwendet habe, und wollte es einfach halten. Das hat für mich funktioniert:

var mapped = [item].map(myMapFunction).pop();

Minimalversion (es6):

Object.entries(obj).reduce((a, [k, v]) => (a[k] = v * v, a), {})

Sie können eine einfache For-In-Schleife durch geordnete Paare verwenden. Ich habe hasOwnProperty() weil Sie drei Eigenschaften (mit Werten) für Ihr Objekt erstellt haben. Die erste Methode erstellt keine Karte. Stattdessen wird die Funktion einfach auf ein einzelnes Element angewendet, was die Ausführung in vielen Situationen erheblich beschleunigen kann.

Die zweite Methode erstellt eine Karte in ähnlicher Weise wie die erste, ist aber wahrscheinlich langsamer als einige andere Antworten hier.

var myObject = { 'a': 1, 'b': 2, 'c': 3 }

//Doesn't create a map, just applies the function to a specific element
function getValue(key) {
  for (var k in myObject) {
    if (myObject.hasOwnProperty(key)) {
      var value = myObject[key]
      return value * value; //stops iteration
    }
  }
}

//creates a map (answers question, but above function is better in some situations)
var newObject = {};
makeMap();

function makeMap() {
    for (var k in myObject) {
        var value = myObject[k];
        newObject[k] = value * value;
    }
}

console.log(newObject); //mapped array
Input: <input id="input" value="" placeholder="a, b or c"><br>
Output:<input id="output"><br>
<button onclick="output.value=getValue(input.value)" >Get value</button>


Wenn Sie nicht nur Werte, sondern auch Schlüssel mit dem map Ping Object.map(valueMapper, keyMapper) ich Object.map(valueMapper, keyMapper) , die sich so verhalten:

var source = { a: 1, b: 2 };
function sum(x) { return x + x }

source.map(sum);            // returns { a: 2, b: 4 }
source.map(undefined, sum); // returns { aa: 1, bb: 2 }
source.map(sum, sum);       // returns { aa: 2, bb: 4 }

Wie wäre es mit einem einzelnen Liner mit sofortiger variabler Zuordnung in JS ( ES6 / ES2015 )?

Syntax des Spread-Operators und des berechneten Schlüsselnamens verwenden :

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

jsbin

Eine andere Version, die reduce verwendet:

let newObj = Object.keys(obj).reduce((p, c) => ({...p, [c]: obj[c] * obj[c]}), {});

jsbin

Erstes Beispiel als Funktion:

const oMap = (o, f) => Object.assign({}, ...Object.keys(o).map(k => ({ [k]: f(o[k]) })));

// To square each value you can call it like this:
let mappedObj = oMap(myObj, (x) => x * x);

jsbin

Wenn Sie ein geschachteltes Objekt rekursiv in einem funktionalen Stil abbilden möchten, können Sie das folgendermaßen tun:

const sqrObjRecursive = (obj) => 
  Object.keys(obj).reduce((newObj, key) => 
    (obj[key] && typeof obj[key] === 'object') ?
      {...newObj, [key]: sqrObjRecursive(obj[key])} :  // recurse.
      {...newObj, [key]: obj[key] * obj[key]}          // square val.
    ,{})       

jsbin

Oder dringender, so:

const sqrObjRecursive = (obj) => {
  Object.keys(obj).forEach(key => {
    if (typeof obj[key] === 'object') obj[key] = sqrObjRecursive(obj[key]);
    else obj[key] = obj[key] * obj[key]
  });
  return obj;
};

jsbin

Seit ES7 / ES2016 können Sie Object.entries statt Object.keys zB wie Object.keys :

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


Vererbte Eigenschaften und die Prototypkette:

In einigen seltenen Situationen müssen Sie möglicherweise ein klassenähnliches Objekt zuordnen, das Eigenschaften eines geerbten Objekts in seiner prototype-chain . In solchen Fällen Object.keys() nicht, da Object.keys() geerbte Eigenschaften nicht aufzählt. Wenn Sie vererbte Eigenschaften for (key in myObj) {...} müssen, sollten Sie for (key in myObj) {...} .

Hier ist ein Beispiel für ein Objekt, das die Eigenschaften eines anderen Objekts erbt und wie Object.keys() in einem solchen Szenario nicht funktioniert.

const obj1 = { 'a': 1, 'b': 2, 'c': 3}
const obj2 = Object.create(obj1);  // One of multiple ways to inherit an object in JS.

// Here you see how the properties of obj1 sit on the 'prototype' of obj2
console.log(obj2)  // Prints: obj2.__proto__ = { 'a': 1, 'b': 2, 'c': 3}

console.log(Object.keys(obj2));  // Prints: an empty Array.

for (key in obj2) {
  console.log(key);              // Prints: 'a', 'b', 'c'
}

jsbin

Aber tu mir bitte einen Gefallen und vermeide Vererbung . :-)


var myObject = { 'a': 1, 'b': 2, 'c': 3 };


Object.prototype.map = function(fn){
    var oReturn = {};
    for (sCurObjectPropertyName in this) {
        oReturn[sCurObjectPropertyName] = fn(this[sCurObjectPropertyName], sCurObjectPropertyName);
    }
    return oReturn;
}
Object.defineProperty(Object.prototype,'map',{enumerable:false});





newObject = myObject.map(function (value, label) {
    return value * value;
});


// newObject is now { 'a': 1, 'b': 4, 'c': 9 }




map-function