J'ai la structure de données suivante dans les objets imbriqués:
const selectableCards = { jobType1 : { card1 : { id : "1", category: "Cat1", title : "Title1", cardText : "Some text.", }, card2 : { id : "2", category: "Cat1", title : "Title2", cardText : "Some text.", }, }, jobType2 : { card1 : { id : "3", category: "Cat2", title : "Title1", cardText : "Some text.", }, card2 : { id : "4", category: "Cat2", title : "Title2", cardText : "Some text.", }, }
Je dois pouvoir trouver une carte par identifiant. J'ai essayé des exemples de ... Comment trouver des objets avec une propriété à l'intérieur d'un autre objet en JavaScript et je ne peux pas comprendre comment traduire la réponse en solution. Je vois qu'il existe une approche ES6 à ce problème, mais pour la vie de moi, je ne peux pas traduire l'exemple ES6 à cet ensemble de données. Comment puis-je faire ceci?
8 Réponses :
Compte tenu de la structure que vous avez fournie, les éléments suivants devraient fonctionner:
const selectableCards = { jobType1: { card1: { id: "1", category: "Cat1", title: "Title1", cardText: "Some text.", }, card2: { id: "2", category: "Cat1", title: "Title2", cardText: "Some text.", }, }, jobType2: { card1: { id: "3", category: "Cat2", title: "Title1", cardText: "Some text.", }, card2: { id: "4", category: "Cat2", title: "Title2", cardText: "Some text.", }, } }; function findCardById(cards, idToFind) { for (const jobType of Object.values(cards)) { const found = Object.values(jobType).find(c => c.id === idToFind); if (found) { return found; } } return null; } console.log(findCardById(selectableCards, "3")); console.log(findCardById(selectableCards, "2"));
Exemple de travail:
function findCardById(cards, idToFind) { for (const jobType in Object.values(cards)) { const found = Object.values(jobType).find(c => c.id === idToFind); if (found) { return found; } } return null; }
Notez que comme TJCrowder l'a suggéré, ce n'est pas très performant s'il y a un très grand nombre d'éléments. Dans un tel cas, il vaut mieux utiliser une boucle for
:
const selectableCards = { jobType1: { card1: { id: "1", category: "Cat1", title: "Title1", cardText: "Some text.", }, card2: { id: "2", category: "Cat1", title: "Title2", cardText: "Some text.", }, }, jobType2: { card1: { id: "3", category: "Cat2", title: "Title1", cardText: "Some text.", }, card2: { id: "4", category: "Cat2", title: "Title2", cardText: "Some text.", }, } }; const idToFind = "3" const foundCard = Object.values(selectableCards).map(Object.values).flat().find(c => c.id === idToFind); console.log(foundCard);
Exemple de travail:
const foundCard = Object.values(selectableCards) // array of values in selectableCards .map(Object.values) // convert each jobType to array of values .flat() // flatten the outer array .find(c => c.id === idToFind); // find the sought value
C'est génial si vous ne traitez pas avec des centaines de milliers d'entre eux (ce que la plupart des gens ne seront pas). Pour les ensembles de données très volumineux, puisqu'il ne court-circuite pas, il vaut probablement mieux utiliser des boucles.
@TJCrowder Merci. J'ai ajouté un exemple avec un court-circuit.
Vous pouvez adopter une approche récursive en examinant l'objet réel ou toutes les valeurs.
const find = (object, key, value) => { if (!object || typeof object !== 'object') return; if (object[key] === value) return object; let result; Object.values(object).some(o => result = find(o, key, value)); return result; }, selectableCards = { jobType1: { card1: { id: "1", category: "Cat1", title: "Title1", cardText: "Some text." }, card2: { id: "2", category: "Cat1", title: "Title2", cardText: "Some text." } }, jobType2: { card1: { id: "3", category: "Cat2", title: "Title1", cardText: "Some text." }, card2: { id: "4", category: "Cat2", title: "Title2", cardText: "Some text." } } }, result = find(selectableCards, 'id', '3'); console.log(result);
Vous pouvez utiliser Object.values
pour obtenir un tableau de toutes les valeurs d'un objet, et la find
méthode vous permet de trouver une entrée dans un tableau qui correspond à un test que vous fournissez (en fonction). Donc (voir commentaires):
const selectableCards = { jobType1 : { card1 : { id : "1", category: "Cat1", title : "Title1", cardText : "Some text.", }, card2 : { id : "2", category: "Cat1", title : "Title2", cardText : "Some text.", }, }, jobType2 : { card1 : { id : "3", category: "Cat2", title : "Title1", cardText : "Some text.", }, card2 : { id : "4", category: "Cat2", title : "Title2", cardText : "Some text.", }, } }; function findCard(selectableCards, cardToFind) { for (const outerKey in selectableCards) { const job = selectableCards[outerKey]; for (const innerKey in job) { const card = job[innerKey]; if (card.id === cardToFind) { return card; } } } } console.log(findCard(selectableCards, "3"));
(Cela n'a l'air verbeux qu'à cause des commentaires explicatifs.)
Exemple en direct:
function findCard(selectableCards, cardToFind) { for (const outerKey in selectableCards) { const job = selectableCards[outerKey]; for (const innerKey in job) { const card = job[innerKey]; if (card.id === cardToFind) { return card; } } } }
Cela renvoie implicitement undefined
s'il ne trouve pas la carte.
Si l'ensemble de données est vraiment massive (vous ne l' avez pas dit qu'il est) et que vous voulez éviter des réseaux temporaires, imbriqués for-in
boucles se faire aussi:
const selectableCards = { jobType1 : { card1 : { id : "1", category: "Cat1", title : "Title1", cardText : "Some text.", }, card2 : { id : "2", category: "Cat1", title : "Title2", cardText : "Some text.", }, }, jobType2 : { card1 : { id : "3", category: "Cat2", title : "Title1", cardText : "Some text.", }, card2 : { id : "4", category: "Cat2", title : "Title2", cardText : "Some text.", }, } }; function findCard(selectableCards, cardToFind) { // Loop through the job(?) objects, which are the values of the // `seletableCards` object's properties for (const job of Object.values(selectableCards)) { // Look for a card in the job's p;roperties' values with a matching `id` const card = Object.values(job).find(({id}) => id === cardToFind); if (card) { // Found it return card; } } } console.log(findCard(selectableCards, "3"));
Exemple en direct:
function findCard(selectableCards, cardToFind) { // Loop through the job(?) objects, which are the values of the // `seletableCards` object's properties for (const job of Object.values(selectableCards)) { // Look for a card in the job's p;roperties' values with a matching `id` const card = Object.values(job).find(({id}) => id === cardToFind); if (card) { // Found it return card; } } }
Une réponse plus basique (et peut-être plus compréhensible)
findCard("2") function findCard(id){ for (let i in selectableCards) { if(i.card1 && i.card1.id === id) { console.log('found in card1'); } else if(i.card2 && i.card2.id === id){ console.log('found in card2'); } } }
Il existe d'autres moyens de le faire, par exemple en utilisant des fonctions d'ordre supérieur, cependant, ce code est fourni pour que vous le compreniez (puisque vous l'avez mentionné dans vos commentaires)
const selectableCards = { jobType1: { card1: { id: "1", category: "Cat1", title: "Title1", cardText: "Some text.", }, card2: { id: "2", category: "Cat1", title: "Title2", cardText: "Some text.", }, }, jobType2: { card1: { id: "3", category: "Cat2", title: "Title1", cardText: "Some text.", }, card2: { id: "4", category: "Cat2", title: "Title2", cardText: "Some text.", }, } }; const targetId = '3'; const result = Object.values(selectableCards) // Flat the first level (the object is now an array) .flatMap(Object.values) // Flat one more level (you can add more exact copies of this line for each additional levels you wish to flat) .find(e => e.id == targetId); // Find the target object console.log(result);
Vous pouvez changer .flatMap(o => Object.values(o))
en seulement .flatMap(Object.values)
.
Vous pouvez produire un objet de recherche pour rechercher rapidement des cartes par leur identifiant .
const selectableCards = {jobType1:{card1:{id:"1",category:"Cat1",title:"Title1",cardText:"Some text."},card2:{id:"2",category:"Cat1",title:"Title2",cardText:"Some text."}},jobType2:{card1:{id:"3",category:"Cat2",title:"Title1",cardText:"Some text."},card2:{id:"4",category:"Cat2",title:"Title2",cardText:"Some text."}}}; const cardsById = new Map( // or Object.fromEntries( Object.values(selectableCards) .flatMap(cards => Object.values(cards)) .map(card => [card.id, card]) ); console.log(cardsById.get("1")); console.log(cardsById.get("4"));
Les objets de recherche sont plus efficaces si vous devez rechercher des données plusieurs fois. Vous générez la structure une fois, puis effectuez toutes vos recherches.
Selon vos préférences et vos besoins, vous pouvez utiliser une Map
ou un Object
. La différence étant que Map
différence entre cardsById.get(1)
et cardsById.get("1")
. Lors de l'utilisation d'un Object
cardsById[1]
et les cardsById["1"]
sont considérées comme identiques.
Je recommande d'utiliser une bibliothèque pour ce type de traitement de données - il est trop facile de se tromper et il est difficile de maintenir des fonctions complexes. Nous avons commencé à utiliser l' analyse d' objets pour la plupart de nos besoins en matière de traitement de données. C'est assez puissant une fois que vous en avez la tête. Voici comment vous répondriez à vos questions
const objectScan = require('object-scan'); const find = (id, data) => objectScan(['*.*.id'], { abort: true, rtn: 'parent', filterFn: ({ value }) => value === id })(data); const selectableCards = {"jobType1":{"card1":{"id":"1","category":"Cat1","title":"Title1","cardText":"Some text."},"card2":{"id":"2","category":"Cat1","title":"Title2","cardText":"Some text."}},"jobType2":{"card1":{"id":"3","category":"Cat2","title":"Title1","cardText":"Some text."},"card2":{"id":"4","category":"Cat2","title":"Title2","cardText":"Some text."}}}; console.log(find('1', selectableCards)); // => { id: '1', // category: 'Cat1', // title: 'Title1', // cardText: 'Some text.' }
Je suggère d'utiliser la bibliothèque appelée d-forest pour trouver un objet profondément imbriqué.
La structure est-elle toujours juste une> carte de travail ou la profondeur varie-t-elle?
Chaque "type" de travail a un sous-ensemble de "travaux" dans les objets "carte". Chaque objet carte a toujours l'identifiant unique. La profondeur des objets est toujours celle-ci.