Adding elements in the array on the basis of an object - javascript

const prefer={"cs":{"c1":true,"c2":true,"c3":false,"c4":true}}
setArray((prevArray)=>{
return prevArray.filter(function(array){
//code here
})
});
I want to set array on the basis of prefer object, like if c1 is true then is want to add it in the array
Do I need to initialize the array too?
In above example array=["c1","c2","c4"] .
Also do we need filter method or can we use some other method

You can use for-in loop to iterate map/object
const prefer = { c1: true, c2: true, c3: false, c4: true };
let arr = [];
for (let key in prefer) {
if (prefer[key]) arr.push(key); // modify how u want to save
// arr.push({ [key]: prefer[key] }); // if u want key and value
}
console.log(arr);

You can express it as follows,
const prefer = { "c1":true, "c2":true, "c3":false, "c4":true }
const output = Object.entries(prefer)
.filter(([, value]) => value) // !!value or Boolean(value) to coerce
.map(([key]) => key)
console.log(output)

This is sort of convoluted, but it works:
const prefer = {
"c1": true,
"c2": true,
"c3": false,
"c4": true
}
var setArray = ( prevArray ) => {
return Object.keys(prevArray).filter(function(val, i) {
if ( prevArray[Object.keys(prevArray)[i]] ) return Object.keys(prevArray)[i];
})
};
console.log( setArray(prefer) );

Related

How to include data to object if element is not falsy?

I have the map:
map(([reportProperties, reportObjectsProperties, textProperties, visibleText]) => {
return { reportObjectsProperties, reportProperties, textProperties, visibleText };
}),
I try to check if all parameters are not falsy include them to result object like this:
map(([reportProperties, reportObjectsProperties, textProperties, visibleText]) => {
if(visibleText)
return { reportObjectsProperties, reportProperties, textProperties, visibleText };
if(reportObjectsProperties && reportObjectsProperties.length)
return { reportObjectsProperties, reportProperties, textProperties, visibleText };
....
}),
How to make this more elegant?
My suggestion is to look into Array.prototype.filter() method paired with
Object.entries to filter out the falsy values. And pair it with a reduce function to reconstruct the new object
I would take this into the following direction:
const arr = [{a: true, b: true, c: false}, {a: false, b: true}]
const excludeKeys = ["c"]
let result = arr.map(obj => {
return Object.entries(obj).filter(([key, value]) => !excludeKeys.includes(key) && value)
.reduce((prev, [key, value]) => ({...prev, [key]: value}), {})
})
This provides a functional and pretty generic interface for filtering out the falsy / excluded object key / values.
Assuming your object is an array, you can check if all values exists using every method. And you don't need map there because you don't do a transformation on your object.
instead of
.map(arr => {
... return arr;
});
do
.filter(row => row.every(cell => typeof cell !== undefined && cell !== null));

Selectively Destructure an object, based on key name

Let's say I have this object:
const someProps = { darkMode: true, underlineMistakes: false, spellingView: (...), grammerView: (...) };
I do not necessarily know the names of any of the props, except that 1+ end in 'View'.
and I want to only destructure the keys that end in 'view', which I'd like to do something like:
const propsEndingInView = Object.keys(someProps).filter(prop => !prop.endsWith('View');
const {
...nonViewProps, // darkMode, underlineMistakes
propsEndingInView // {spellingView: (...), grammerView: (...)}
} = someProps;
I need to somehow separate the two kinds of props, preferably while
I can't think how to do this, or even if it's possible.
Destructuring is just way to get the properties you already know. You can't do this with destructuring. You can create a custom method to filter out the keys to get a subset of the object
const someProps = {
darkMode: true,
underlineMistakes: false,
spellingView: 'spellingView',
grammerView: 'grammerView'
};
const subset = Object.fromEntries(
Object.entries(someProps).filter(([k]) => k.endsWith('View'))
)
console.log(subset)
This cannot be done by destructuring, but you can write some code to do it. For example:
const extract = (obj, regex) =>
Object
.entries(obj)
.filter(([k]) => (typeof k === 'string') && regex.test(k))
.reduce((out, [k, v]) => (
out[k] = v,
out
), {})
const someProps = { darkMode: true, underlineMistakes: false, spellingView: '(...)', grammerView: '(...)' };
const propsEndingInView = extract(someProps, /View$/)
console.log(propsEndingInView)
If I understand correctly you want to end up with an object that only contains properties from someProps whose names end in View. You can do something like:
const viewProps = Object.keys(someProps).reduce((props, propName) => {
// Here we check whether propName ends in View
// If it does we add it to the object, if not we leave the object as it is
return propName.match(/View$/) ? { ...props, [propName]: someProps[propName] } : props;
}, {});
Does that help? You can find the documentation about Array.reduce here.

Two object arrays: merge with same key

I have two object arrays. I want to merge with key with value
var a = [{"fit":["34","32","30","28"],"size":["x"]}]
var b = [{"size":["s","m","xl"],"fit":["36"]}]
Expected Output should be
Obj=[{"fit":["34","32","30","28","36"],"size":["x,"s","m","xl"]}]
My Code is
let arr3 = [];
b.forEach((itm, i) => {
arr3.push(Object.assign({}, itm, a[i]));
});
alert(JSON.stringify(arr3))
it gives [{"size":["x"],"fit":["34","32","30","28"]}] which wrong.
Use Array.reduce().
// Combine into single array (spread operator makes this nice)
const myArray = [...a, ...b];
// "reduce" values in array down to a single object
const reducedArray = myArray.reduce((acc, val) => {
return [{fit: [...acc.fit, ...val.fit], size: [...acc.size, ...val.size]}];
});
Edit: if you want the reducer to merge objects regardless of what keys and fields it has then you can do by iterating over the keys of the objects and merging them dynamically:
const reducedArray = myArray.reduce((acc, val) => {
const returnObject = {};
for (const eaKey in acc) {
returnObject[eaKey] = [...acc[eaKey], ...val[eaKey]];
}
return [returnObject];
});
If the fields of the objects aren't guaranteed keys then you will need to get even more dynamic in detecting the type of merge and how to do it, but it's possible and I will leave that as an exercise for you to figure out. :)
Note that if there are duplicate values in each of the "fit" and "size" arrays, they will not be deduplicated. You'd have to do that manually as a separate step either with extra logic in the reduce function or afterwards.
combine a and b in a single array then reduce it starting with an array having an object with empty fit and size arrays:
var a = [{ fit: ["34", "32", "30", "28"], size: ["x"] }];
var b = [{ size: ["s", "m", "xl"], fit: ["36"] }];
var obj = [...a, ...b].reduce(
(acc, curr) => {
Object.keys(curr).forEach(k => {
acc[0][k] = [...new Set([...(acc[0][k] || []), ...curr[k]])];
});
return acc;
},
[{}]
);
console.log(obj);
You can create a combine function that takes fit and size from any two objects and merges them.
Use it as a reducer to combine everything.
let combine = ({fit, size}, {fit: fit2, size: size2}) =>
({ fit: [...fit, ...fit2], size: [...size, ...size2] });
let result = [...a, ...b].reduce(combine);
Example:
var a = [{"fit":["34","32","30","28"],"size":["x"]}, {"fit": ["10", "11"], "size":["xxxxxxxxl"]}]
var b = [{"size":["s","m","xl"],"fit":["36"]}];
let combine = ({fit, size}, {fit: fit2, size: size2}) =>
({ fit: [...fit, ...fit2], size: [...size, ...size2] });
let result = [...a, ...b].reduce(combine);
console.log(result);
If you don't want to use the keys directly you could try
const arr3 = b.reduce((carry, current, index) => {
Object.keys(current)
.forEach(key => {
Object.assign(carry, { [key]: Array.prototype.concat.call(current[key], a[index][key])});
});
return carry;
}, {});

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>)
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 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 yourmyBook 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>`)
);
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 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
}
})

Get Keys With Value From Inside Object

I have an object like this:
trueOptions = {
trueOption1 : true,
trueOption2 : true,
trueOption3 : false,
trueOption4 : false,
trueOption5 : true
}
I want to get the keys for the items with true values from inside the object.
How can I get these items?
Thanks.
You can use filter and map on Object.entries
const options = {
trueOption1: true,
trueOption2: true,
trueOption3: false,
trueOption4: false,
trueOption5: true
}
const trueOptions = Object.entries(options).filter(option=>option[1]).map(option=>option[0])
console.log(trueOptions)
You can use Object.keys() to iterate through each key and then use array#filter to filter out keys whose value is true.
const trueOptions = { trueOption1 : true, trueOption2 : true, trueOption3 : false, trueOption4 : false, trueOption5 : true },
result = Object.keys(trueOptions).filter(k => trueOptions[k]);
console.log(result);
Option 1
See Object.entries(), Array.prototype.filter(), and Array.prototype.map() for more info.
// Input.
const options = {option1: true,option2: true,option3: false,option4: false,option5: true}
// Trues.
const trues = obj => Object.entries(obj).filter(([key, value]) => value).map(([key]) => key)
// Output.
const output = trues(options)
// Proof.
console.log(output)
Option 2
See Object.keys() and JSON for more info.
// Input.
const options = {option1: true,option2: true,option3: false,option4: false,option5: true}
// Trues.
const trues = obj => Object.keys(JSON.parse(JSON.stringify(obj, (k, v) => v || undefined)))
// Output.
const output = trues(options)
// Proof.
console.log(output)
Object.keys(trueOptions).forEach(d=>{if(trueOptions[d] != true){delete trueOptions[d];}})
Object.keys(trueOptions)

Categories

Resources