简体   繁体   中英

Dynamically get values of object from array

Let's say I have an Object myBook and an array allCategories .

const allCategories = ["sciencefiction", "manga", "school", "art"];

const myBook = {
   isItScienceFiction: true,
   isItManga: false,
   isItForKids: false
}

What I want : Loop over categories to check the value of Book, for example, check if "sciencefiction" exists in my Book Object and then check it's value

What I have tried :

1) With indexOf

allCategories.map((category) => {
    Object.keys(myBook).indexOf(category) 
    // Always returns -1 because "sciencefiction" doesn't match with "isItScienceFiction"
});

2) With includes

allCategories.map((category) => {
    Object.keys(myBook).includes(category) 
    // Always returns false because "sciencefiction" doesn't match with "isItScienceFiction"
});

Expected output :

allCategories.map((category) => {
   // Example 1 : Returns "sciencefiction" because "isItScienceFiction: true"
   // Example 2 : Returns nothing because "isItManga: false"
   // Example 3 : Returns nothing because there is not property in myBook with the word "school"
   // Example 4 : Returns nothing because there is not property in myBook with the word "art"


   // If category match with myBook categories and the value is true then
    return (
         <p>{category}</p>
    );
});

If you need more information, just let me know, I'll edit my question.

You could use filter and find methods to return new array of categories and then use map method to return array of elements.

 const allCategories = ["sciencefiction", "manga", "school", "art"]; const myBook = {isItScienceFiction: true, isItManga: false, isItForKids: false} const result = allCategories.filter(cat => { const key = Object.keys(myBook).find(k => k.slice(4).toLowerCase() === cat); return myBook[key] }).map(cat => `<p>${cat}</p>`) console.log(result) 

You can also use reduce instead of filter and map and endsWith method.

 const allCategories = ["sciencefiction", "manga", "school", "art"]; const myBook = {isItScienceFiction: true,isItManga: false,isItForKids: false} const result = allCategories.reduce((r, cat) => { const key = Object.keys(myBook).find(k => k.toLowerCase().endsWith(cat)); if(myBook[key]) r.push(`<p>${cat}</p>`) return r; }, []) console.log(result) 

You can use

Object.keys(myBook).forEach(function(key){console.log(myBook[key])})

... place you code instead of console.log . This can do the trick without hard coding and also the best practice.

You should really not keep a number of properties containing booleans. While that might work for 1, 2 or 3 categories, for a few hundred it won't work well. Instead, just store the categories in an array:

 const myBook = {
   categories: ["sciencefiction", "manga", "kids"],
 };

If you got some object with the old structure already, you can easily convert them:

 const format = old => {
  const categories = [];

  if(old.isItScienceFiction)
    categories.push("sciencefiction");
  if(old.isItManga)
     categories.push("manga");
  if(old.isItForKids)
     categories.push("kids");

   return { categories };
 };

Now to check wether a book contains a certain category:

  const isManga = myBook.categories.includes("manga");

And your rendering is also quite easy now:

 myBook.categories.map(it => <p>{it}</p>)

You could create a Map for the the categories and keys of object:

 const allCategories = ["sciencefiction", "manga", "school", "art"], myBook = { isItScienceFiction:true, isItManga:false, isItForKids:false } const map = Object.keys(myBook) .reduce((r, k) => r.set(k.slice(4).toLowerCase(), k), new Map); /* map: {"sciencefiction" => "isItScienceFiction"} {"manga" => "isItManga"} {"forkids" => "isItForKids"} */ allCategories.forEach(key => { let keyInObject = map.get(key); // the key name in object let value = myBook[keyInObject]; // value for the key in object console.log(key, keyInObject, value) if(keyInObject && value) { // do something if has the current key and the value is true } }) 

Use Array.filter() and Array.find() with a RegExp to find categories that have matching keys. Use Array.map() to convert the categories to strings/JSX/etc...

 const findMatchingCategories = (obj, categories) => { const keys = Object.keys(obj); return allCategories .filter(category => { const pattern = new RegExp(category, 'i'); return obj[keys.find(c => pattern.test(c))]; }) .map(category => `<p>${category}</p>`); }; const allCategories = ["sciencefiction", "manga", "school", "art"]; const myBook = { isItScienceFiction: true, isItManga: false, isItForKids: false }; const result = findMatchingCategories(myBook, allCategories); console.log(result); 

You can try like this:

 const allCategories = ["sciencefiction", "manga", "school", "art"]; const myBook = { isItScienceFiction: true, isItManga: false, isItForKids: false }; const myBookKeys = Object.keys(myBook); const result = allCategories.map(category => { const foundIndex = myBookKeys.findIndex(y => y.toLowerCase().includes(category.toLowerCase())); if (foundIndex > -1 && myBook[myBookKeys[foundIndex]]) return `<p>${category}</p>`; }); console.log(result); 

You can modify the key names in myBook object for easy lookup like:

const allCategories = ["sciencefiction", "manga", "school", "art"];

const myBook = {
  isItScienceFiction: true,
  isItManga: false,
  isItForKids: false
}

const modBook = {}

Object.keys(myBook).map((key) => {
  const modKey = key.slice(4).toLowerCase()
  modBook[modKey] = myBook[key]
})

const haveCategories = allCategories.map((category) => {
  if (modBook[category]) {
    return <p>{category}</p>
  }
  return null
})
console.log(haveCategories)

Converting sciencefiction to isItScienceFiction is not possible and looping all the keys of myBook for every category is not optimal.

But converting isItScienceFiction to sciencefiction is pretty easy, so you can create newMyBook from your myBook and use it instead to check.

Creating newMyBook is a one time overhead.

 const allCategories = ["sciencefiction", "manga", "school", "art"]; const myBook = {isItScienceFiction: true,isItManga: false,isItForKids: false}; const newMyBook = Object.keys(myBook).reduce((a, k) => { return { ...a, [k.replace('isIt', '').toLowerCase()]: myBook[k] }; }, {}); console.log( allCategories.filter(category => !!newMyBook[category]).map(category => `<p>${category}</p>`) ); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM