it-swarm.com.de

Filtern Sie die Objekteigenschaften nach dem Schlüssel in ES6

Sagen wir, ich habe ein Objekt:

{
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

Ich möchte ein anderes Objekt erstellen, indem ich das Objekt oben filtere, damit ich so etwas habe.

 {
    item1: { key: 'sdfd', value:'sdfd' },
    item3: { key: 'sdfd', value:'sdfd' }
 }

Ich bin auf der Suche nach einer sauberen Methode, um dies mit Es6 zu erreichen, daher stehen mir Spread-Operatoren zur Verfügung.

125
29er

Wenn Sie eine Liste zulässiger Werte haben, können Sie diese auf einfache Weise in einem Objekt beibehalten, indem Sie Folgendes verwenden:

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.keys(raw)
  .filter(key => allowed.includes(key))
  .reduce((obj, key) => {
    obj[key] = raw[key];
    return obj;
  }, {});

console.log(filtered);

Dies verwendet:

  1. Object.keys , um alle Eigenschaften in raw (den Originaldaten) aufzulisten
  2. Array.prototype.filter um Schlüssel auszuwählen, die in der erlaubten Liste vorhanden sind, mit
    1. Array.prototype.includes um sicherzustellen, dass sie vorhanden sind
  3. Array.prototype.reduce um ein neues Objekt nur mit den erlaubten Eigenschaften zu erstellen.

Dadurch wird eine flache Kopie mit den zulässigen Eigenschaften erstellt (die Eigenschaften selbst werden jedoch nicht kopiert).

Sie können auch den Objektverbreitungsoperator verwenden, um eine Reihe von Objekten zu erstellen, ohne sie zu mutieren (dank rjerue für die Erwähnung ):

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.keys(raw)
  .filter(key => allowed.includes(key))
  .reduce((obj, key) => {
    return {
      ...obj,
      [key]: raw[key]
    };
  }, {});

console.log(filtered);

Wenn Sie aus trivialen Gründen die unerwünschten Felder aus den Originaldaten entfernen möchten (was ich nicht empfehlen würde, da es sich um einige hässliche Mutationen handelt) , Sie könnten das includes Häkchen folgendermaßen umkehren:

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

Object.keys(raw)
  .filter(key => !allowed.includes(key))
  .forEach(key => delete raw[key]);

console.log(raw);

Ich füge dieses Beispiel hinzu, um eine mutationsbasierte Lösung zu zeigen, schlage aber nicht vor, es zu verwenden.

341
ssube

Wenn Sie mit der ES6-Syntax einverstanden sind, finde ich, dass dies der sauberste Weg ist, wie unter hier und hier angegeben:

const data = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const { item2, ...newData } = data;

Nun enthält newData:

{
  item1: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

Oder, wenn Sie den Schlüssel als Zeichenfolge gespeichert haben:

const key = 'item2';
const { [key]: _, ...newData } = data;

Im letzteren Fall wird [key] in item2 konvertiert. Da Sie jedoch eine const-Zuweisung verwenden, müssen Sie einen Namen für die Zuordnung angeben. _ steht für einen Wegwerfwert.

Allgemeiner:

const { item2, ...newData } = data; // Assign item2 to item2
const { item2: someVarName, ...newData } = data; // Assign item2 to someVarName
const { item2: _, ...newData } = data; // Assign item2 to _
const { ['item2']: _, ...newData } = data; // Convert string to key first, ...

Dies reduziert nicht nur Ihren Betrieb auf einen Einzeiler, sondern Sie müssen auch nicht wissen, was die anderen Schlüssel sind (diejenigen, die Sie behalten möchten).

45
Ryan H.

Der sauberste Weg, den Sie finden können, ist mit Lodash # pick

const _ = require('lodash');

const allowed = ['item1', 'item3'];

const obj = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

const filteredObj = _.pick(obj, allowed)
29
Guy Segev

Nichts, was noch nicht gesagt wurde, aber einige Antworten zu einer allgemeinen ES6-Antwort zusammenfassen

const raw = {
  item1: { key: 'sdfd', value: 'sdfd' },
  item2: { key: 'sdfd', value: 'sdfd' },
  item3: { key: 'sdfd', value: 'sdfd' }
};

const filteredKeys = ['item1', 'item3'];

const filtered = filteredKeys
  .reduce((obj, key) => ({ ...obj, [key]: raw[key] }), {});

console.log(filtered);

12
Clemens Helm

Nur eine andere Lösung in eine Zeile Code .

Ich habe mit der Funktion " Destructuring " gespielt:

const raw = {
    item1: { key: 'sdfd', value: 'sdfd' },
    item2: { key: 'sdfd', value: 'sdfd' },
    item3: { key: 'sdfd', value: 'sdfd' }
  };
var myNewRaw = (({ item1, item3}) => ({ item1, item3 }))(raw);
console.log(myNewRaw);

11
Novy

Sie können ein generisches ofilter (implementiert mit generischem oreduce) hinzufügen, um Objekte auf die gleiche Weise zu filtern wie Arrays -

const oreduce = (f, acc, o) =>
  Object
    .entries (o)
    .reduce
      ( (acc, [ k, v ]) => f (acc, v, k, o)
      , acc
      )

const ofilter = (f, o) =>
  oreduce
    ( (acc, v, k, o)=>
        f (v, k, o)
          ? Object.assign (acc, {[k]: v})
          : acc
    , {}
    , o
    )

Wir können es hier sehen -

const data =
  { item1: { key: 'a', value: 1 }
  , item2: { key: 'b', value: 2 }
  , item3: { key: 'c', value: 3 }
  }

console.log
  ( ofilter
      ( (v, k) => k !== 'item2'
      , data
      )
      // [ { item1: { key: 'a', value: 1 } }
      // , { item3: { key: 'c', value: 3 } }
      // ]

  , ofilter
      ( x => x.value === 3
      , data
      )
      // [ { item3: { key: 'c', value: 3 } } ]
  )

Überprüfen Sie die Ergebnisse in Ihrem eigenen Browser.

const oreduce = (f, acc, o) =>
  Object
    .entries (o)
    .reduce
      ( (acc, [ k, v ]) => f (acc, v, k, o)
      , acc
      )

const ofilter = (f, o) =>
  oreduce
    ( (acc, v, k, o)=>
        f (v, k, o)
          ? Object.assign (acc, { [k]: v })
          : acc
    , {}
    , o
    )

const data =
  { item1: { key: 'a', value: 1 }
  , item2: { key: 'b', value: 2 }
  , item3: { key: 'c', value: 3 }
  }

console.log
  ( ofilter
      ( (v, k) => k !== 'item2'
      , data
      )
      // [ { item1: { key: 'a', value: 1 } }
      // , { item3: { key: 'c', value: 3 } }
      // ]

  , ofilter
      ( x => x.value === 3
      , data
      )
      // [ { item3: { key: 'c', value: 3 } } ]
  )

Diese beiden Funktionen können auf viele Arten implementiert werden. Ich habe mich dazu entschieden, an Array.prototype.reduce in oreduce anzuhängen, aber Sie könnten es genauso einfach von Grund auf schreiben

6
user633183

So habe ich es kürzlich gemacht:

const dummyObj = Object.assign({}, obj);
delete dummyObj[key];
const target = Object.assign({}, {...dummyObj});
3
Rajat Saxena

Huckepack auf ssube's answeranswer .

Hier ist eine wiederverwendbare Version.

Object.filterByKey = function (obj, predicate) {
  return Object.keys(obj)
    .filter(key => predicate(key))
    .reduce((out, key) => {
      out[key] = obj[key];
      return out;
    }, {});
}

Um es anzurufen, benutze

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

var filtered = Object.filterByKey(raw, key => 
  return allowed.includes(key));
});

console.log(filtered);

Das Schöne an den ES6-Pfeilfunktionen ist, dass Sie allowed nicht als Parameter übergeben müssen.

3
Evan Plaice

ok, wie wäre es mit diesem Einzeiler

    const raw = {
      item1: { key: 'sdfd', value: 'sdfd' },
      item2: { key: 'sdfd', value: 'sdfd' },
      item3: { key: 'sdfd', value: 'sdfd' }
    };

    const filteredKeys = ['item1', 'item3'];

    const filtered = Object.assign({}, ...filteredKeys.map(key=> ({[key]:raw[key]})));
3
inabramova

Sie können so etwas tun:

const base = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const filtered = (
    source => { 
        with(source){ 
            return {item1, item3} 
        } 
    }
)(base);

// one line
const filtered = (source => { with(source){ return {item1, item3} } })(base);

Dies funktioniert, ist jedoch nicht sehr klar, und die with-Anweisung wird nicht empfohlen ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with ).

2
Bouni

Eine einfachere Lösung ohne filter kann mit Object.entries() anstelle von Object.keys() erreicht werden

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.entries(raw).reduce((acc,Elm)=>{
  const [k,v] = Elm
  if (allowed.includes(k)) {
    acc[k] = v 
  }
  return acc
},{})
2
Itai Noam

Die Antworten hier sind auf jeden Fall geeignet, aber sie sind etwas langsam, da sie für jede Eigenschaft im Objekt durch die Whitelist gezogen werden müssen. Die Lösung unten ist für große Datensätze viel schneller, da sie nur einmal die Whitelist durchläuft: 

const data = {
  allowed1: 'blah',
  allowed2: 'blah blah',
  notAllowed: 'woah',
  superSensitiveInfo: 'whooooah',
  allowed3: 'bleh'
};

const whitelist = ['allowed1', 'allowed2', 'allowed3'];

function sanitize(data, whitelist) {
    return whitelist.reduce(
      (result, key) =>
        data[key] !== undefined
          ? Object.assign(result, { [key]: data[key] })
          : result,
      {}
    );
  }

  sanitize(data, whitelist)
2
Joey Grisafe

Sie können es jetzt mit der MethodeObject.fromEntrieskürzer und einfacher machen (Browserunterstützung prüfen):

const raw = { item1: { prop:'1' }, item2: { prop:'2' }, item3: { prop:'3' } };

const allowed = ['item1', 'item3'];

const filtered = Object.fromEntries(Object.entries(raw).filter(([key, val])=>allowed.includes(key)));

lesen Sie mehr über: Object.fromEntries

0
dudi harush

OK, wie wäre es damit:

const myData = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

function filteredObject(obj, filter) {
  if(!Array.isArray(filter)) {
   filter = [filter.toString()];
  }
  const newObj = {};
  for(i in obj) {
    if(!filter.includes(i)) {
      newObj[i] = obj[i];
    }
  }
  return newObj;
}

und nenne es so:

filteredObject(myData, ['item2']); //{item1: { key: 'sdfd', value:'sdfd' }, item3: { key: 'sdfd', value:'sdfd' }}
0
Alireza

Geben Sie während der Schleife nichts zurück, wenn bestimmte Eigenschaften/Schlüssel gefunden werden, und fahren Sie mit dem Rest fort:

const loop = product =>
Object.keys(product).map(key => {
    if (key === "_id" || key === "__v") {
        return; 
    }
    return (
        <ul className="list-group">
            <li>
                {product[key]}
                <span>
                    {key}
                </span>
            </li>
        </ul>
    );
});
0
Ryan Dhungel

Diese Funktion filtert ein Objekt anhand einer Liste von Schlüsseln. Dies ist effizienter als die vorherige Antwort, da es nicht erforderlich ist, Array.filter zu verwenden, bevor Sie die Funktion zum Abrufen aufrufen. also sein O(n) im Gegensatz zu O (n + gefiltert)

function filterObjectByKeys (object, keys) {
  return Object.keys(object).reduce((accum, key) => {
    if (keys.includes(key)) {
      return { ...accum, [key]: object[key] }
    } else {
      return accum
    }
  }, {})
}
0
Khaled Osman

Sie können einen bestimmten Schlüssel auf Ihrem Objekt entfernen

items={
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

// Example 1
var key = "item2";
delete items[key]; 

// Example 2
delete items["item2"];

// Example 3
delete items.item2;
0
Esin ÖNER

Es gibt viele Möglichkeiten, dies zu erreichen. Die akzeptierte Antwort verwendet einen Keys-Filter-Reduce-Ansatz, der nicht der beste ist.

Verwenden Sie stattdessen eine for...in-Schleife zum Durchlaufen von Schlüsseln eines Objekts oder das Durchlaufen der zulässigen Schlüssel und then zum Erstellen eines neuen Objekts ist ~ 50% performanterein.

const obj = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const keys = ['item1', 'item3'];

function keysReduce (obj, keys) {
  return keys.reduce((acc, key) => {
    if(obj[key] !== undefined) {
      acc[key] = obj[key];
    }
    return acc;
  }, {});
};

function forInCompose (obj, keys) {
  const returnObj = {};
  for (const key in obj) {
    if(keys.includes(key)) {
      returnObj[key] = obj[key]
    }
  };
  return returnObj;
};

keysReduce(obj, keys);   // Faster if the list of allowed keys are short
forInCompose(obj, keys); // Faster if the number of object properties are low

ein. Siehe jsPerf für die Benchmarks eines einfachen Anwendungsfalls. Die Ergebnisse unterscheiden sich je nach Browser.

0
d4nyll