key:value in Objekt finden
ebody
- javascript
1 Rolf B0 Raketenwilli0 Matthias Fulde
Hallo,
jedes key:value
paar aus searchKeyValuePair[]
soll in inThisObject{}
gesucht werden und jeder Erfolg mit true
gespeichert werden. Ich muss festhalten, wie oft es einen Treffer gab.
/** Prüfe jedes key:value paar... */
const searchKeyValuePair = [
{Title: 'Batman'},
{Genre: 'Science-Fiction'},
{Title: 'Prometheus'},
{Duration: 1},
{Title: 'Prometheus'},
];
/** ...ob es in dem Array vorkommt */
const inThisObject = {
Title: 'Prometheus',
Genre: 'Science-Fiction',
Tags: 'Weltall',
Duration: 2
};
Probiert habe ich schon sehr viel, siehe auskommentierten Code.. Das ist jetzt die aktuellste Version:
/**
Erzeugt ein Array aus searchKeyValuePair[] und aus jedem Objekt ein Array.
[
['Title', 'Batman'],
['Genre', 'Science-Fiction'],
['Title', 'Prometheus'],
...
]
*/
const arrSearchKeyValuePairs = searchKeyValuePair.map(searchItem => Object.entries(searchItem));
console.log('arrSearchKeyValuePairs: ', arrSearchKeyValuePairs);
/**
Erzeugt ein Array aus inThisObject[] und aus jedem key:value ein Array.
[
['Title', 'Prometheus'],
['Genre', 'Science-Fiction'],
['Tags', 'Weltall'],
['Duration', 2],
]
*/
const arrInThisObject = Object.entries(inThisObject);
console.log('arrInThisObject: ', arrInThisObject);
console.log('result: ', arrSearchKeyValuePairs.filter(item => arrInThisObject.some(item)));
Aber ich bekomme es einfach nicht hin. Hat jemand einen Tipp?
Gruß ebody
Hallo ebody,
wieder was gelernt. Object.entries kannte ich nicht 😂
Letztlich erzeugst Du auf diesem Weg aus searchKeyValuePair und inThisObject kompatible Strukturen, nämlich ein Array von Arrays mit zwei Einträgen, in denen jeweils Eigenschaftsname und Wert stehen.
Bei arrSearchKeyValuePair bist Du aber über das Ergebnis im Irrtum, denn Object.entries erzeugt ein Array aus Arraypärchen, ein Pärchen pro Objekteigenschaft, und deshalb sieht arrSearchKeyValuePair so aus:
[
[['Title', 'Batman']],
[['Genre', 'Science-Fiction']],
[['Title', 'Prometheus']],
...
]
Du sieht das zusätzliche Klammerpaar? Das willst Du nicht. Du müsstest aus dem map Callback das Ergebnis Object.entries(searchItem)[0]
zurückgeben. Dann käme das raus, was Du Dir gedacht hast.
Aber dann kommst Du mit some, und some braucht eine Callback-Funktion. Du übergibst aber eins von diesen Arrays mit zwei Einträgen. D.h. das zentrale Problem, wie Du in einem Objekt eine Eigenschaft findest, deren Name Du erst zur Laufzeit kennst, hast Du nicht gelöst.
Für eine Lösung wäre aber auch noch die Frage interessant: wie sieht es mit case-sensitivity aus? Wenn Du im searchKeyValuePair den Eintrag { title: 'Batman' } hast, soll dieser Eintrag die Eigenschaft Title
in inThisObject abfragen? Also kleines title vs großes Title? Nehmen wir erstmal an, dass Du dafür keinen Treffer willst.
Ob Du dann .filter auf searchKeyValuePairs oder arrSearchKeyValuePairs anwendest, ist ziemlich egal. Ich würde hier noch die Frage stellen, ob searchKeyValuePairs tatsächlich so aussehen muss, wie es aussieht. Ein keyValuePair sollte so aussehen:
{ key: 'Title', value: 'Batman' }
,
denn dann
Wenn Du deine searchKeyValuePairs so aufbaust, kannst Du auf Object.entries ganz verzichten. Statt dessen rufst Du filter direkt auf searchKeyValuePairs auf, schaust mit der hasOwnProperty Methode nach, ob inThisObject eine Eigenschaft mit dem Namen hat, der in searchItem.key steht und vergleichst dann die Werte. Das ist ein Einzeiler.
Statt hasOwnProperty könnte man auch den in Operator verwenden (Huch, der fehlt im Selfwiki?!), aber in
liefert auch für geerbte Eigenschaften UND Methoden true - das kann nach hinten losgehen.
Links:
Rolf
Hallo an alle,
vielen Dank für eure Infos und Lösungsansätze. Ich denke, ich habe es jetzt umgesetzt bekommen.
/** Prüfe jedes key:value paar... */
const searchKeyValuePair = [
{Title: 'Batman'},
{Genre: 'Science-Fiction'},
{Title: 'Prometheus'},
{Duration: 1},
{Title: 'Prometheus'},
{Genre: 'Batman'},
{Title: ''},
];
/** ...ob es in dem Array vorkommt */
const inThisObject = {
Title: 'Prometheus',
Genre: 'Science-Fiction',
Tags: 'Weltall',
Duration: 2
};
/** Filter alle das Array searchKeyValuePair, so dass nur die key:value Paare übrig bleiben, die in inThisObject vorkommen. */
let data = searchKeyValuePair.filter(search =>
/** Enthält inThisObject den Key von search (z.B. {Title: 'Batman'})? */
inThisObject.hasOwnProperty(Object.keys(search).toString())
/** Enthält der Wert von search (z.B. {Title: 'Batman'}) den gleichen Wert wie inThisObject['mit dem aktuellen Key']? */
&& Object.values(search).includes(inThisObject[Object.keys(search).toString()])
);
console.log('data: ', data);
Für eine Lösung wäre aber auch noch die Frage interessant: wie sieht es mit case-sensitivity aus?
In dem Fall nicht notwendig, da die Keys auf jeden Fall identisch sind.
Ich würde hier noch die Frage stellen, ob searchKeyValuePairs tatsächlich so aussehen muss, wie es aussieht.
Wäre so auch möglich { key: 'Title', value: 'Batman' }
. Gut zu wissen, dass man Objekte auch so schreiben kann.
Was mir darüber hinaus noch auffällt ist, dass dein Array searchKeyValuePairs doppelte Einträge enthält. Entspricht das deinen Daten oder oder sind die key-value Paare in Wirklichkeit eindeutig?
Entspricht den Daten und soll so sein.
Gruß ebody
Hallo ebody,
Wäre so auch möglich
{ key: 'Title', value: 'Batman' }
. Gut zu wissen, dass man Objekte auch so schreiben kann.
Das hast Du gewusst. Das ist nichts anders als { Title: 'Batman'}
, nur mit zwei Eigenschaften statt einer. Der Vorteil ist aber, dass Du bei meinem Vorschlag die Eigenschaftsnamen kennst und nicht erst heraussuchen musst. Deine Schreibweise kann dann interessant werden, wenn deine SearchItems nach mehr als einer Eigenschaft gleichzeitig suchen sollen.
....filter(search =>
/** Enthält inThisObject den Key von search (z.B. {Title: 'Batman'})? */
inThisObject.hasOwnProperty(Object.keys(search).toString())
/** Enthält der Wert von search (z.B. {Title: 'Batman'}) den gleichen Wert wie inThisObject['mit dem aktuellen Key']? */
&& Object.values(search).includes(inThisObject[Object.keys(search).toString()]))
Weia. Mit search.key
statt Object.keys(search).toString()
wäre das deutlich lesbarer. Aber wenn Du unbedingt bei deiner Form der Searchitems bleiben willst, dann mach es so:
....filter(search => {
/** Zu findendes Property ist einziger Key in search (z.B. {Title: 'Batman'}) */
const key = Object.keys(search)[0];
/** Enthält inThisObject den Key ? */
/** und stimmt search[key] mit dem Wert von inThisObject[key] überein? */
return inThisObject.hasOwnProperty(key) && search[key] == inThisObject[key])
})
Man muss jetzt geschweifte Klammern um den Body der Pfeilfunktion setzen und das return-Statement hinschreiben, weil eine lokale Variable deklariert wird. Das kann man vermeiden, indem man die lokale Variable als Parameter tarnt:
....filter((search, key) =>
/** Zu findendes Property ist einziger Key in search (z.B. {Title: 'Batman'}) */
inThisObject.hasOwnProperty(key = Object.keys(search)[0])
/** Stimmt search[key] mit dem Wert von inThisObject[key] überein? */
&& inThisObject[key] == search[key])
)
aber das ist ein Beispiel für üblen und kaum verständlichen Code und nicht zu empfehlen. Ein Minifizierer darf sowas vielleicht produzieren, aber lesbarer Code ist das nicht.
Was spricht dagegen?
Rolf
Ich vermute aus dem Inhalt, Du willst eigentlich:
const haystack = [
[
{Title: 'Batman'},
{Genre: 'Science-Fiction'}
], [
{Title: 'Prometheus'},
{Duration: 1}
], [
{Title: 'Prometheus'}
]
];
console.log ( haystack);
Den Heuhaufen kannst Du mit
haystack.forEach (
// item => console.log( item )
item => item.forEach(
pair => showKeyValue( pair )
)
)
function showKeyValue( o ) {
//console.log( o );
const arr = Object.keys( o );
//console.log( arr );
arr.forEach(
key => console.log( key + ' = ' + o[key] )
)
}
ausgeben. Dafür bekomme ich sicher gleich „Dresche“, weil das Jahr 2010 nach irgendetwas ruft… Aber ich hab schon mal das passende Ergebnis:
[
[ { Title: 'Batman' }, { Genre: 'Science-Fiction' } ],
[ { Title: 'Prometheus' }, { Duration: 1 } ],
[ { Title: 'Prometheus' } ]
]
Title = Batman
Genre = Science-Fiction
Title = Prometheus
Duration = 1
Title = Prometheus
Naja. Und wenn Du schon dabei bist, sollte es kein langer Weg sein, um
Hallo ebody,
dass deine Objekt-Representation der key-value Paare nicht optimal ist, hat Rolf ja schon geschrieben, ebenso zur Problematik mit der case sensitivity.
Was mir darüber hinaus noch auffällt ist, dass dein Array searchKeyValuePairs
doppelte Einträge enthält. Entspricht das deinen Daten oder oder sind die key-value Paare in Wirklichkeit eindeutig?
Falls du wie in deinem Beispiel doppelte Einträge haben solltest und dann, wie von Rolf vorgeschlagen, filter
auf dem Array searchKeyValuePairs
aufrufen und checken würdest, ob der jeweilige Eintrag in dem Objekt inThisObject
vorhanden ist, würdest du Einträge gegebenenfalls mehrfach zählen, was du vermutlich nicht möchtest.
Für dein konkretes Beispiel würdest du 3 Treffer bekommen, da das Paar (Title, Prometheus) doppelt gezählt wird.
Für diesen Ansatz müsstest du also zunächst sicherstellen, dass die key-value Paare höchstens einmal vorkommen.
Oder du testest anders herum, das heißt, du filterst die Einträge in inThisObject
indem du prüfst, ob der Eintrag in searchKeyValuePairs
enthalten ist.
Viele Grüße,
Matthias