Check for a key inside In array of objects - javascript

I am trying to find the best way to check whether an object key is present inside multiple objects present in an array which will provide a boolean as output
[{alert:hi},{alert:bye},{}]
From the above example basically what I am trying to achieve is if any one object is missing the alert object key the output should be as false or anything

You can iterate your array with every(). Something like this:
const objects = [{alert:'hi'},{alert:'bye'},{}];
const every = objects.every(obj => obj.hasOwnProperty('alert'));
console.log(every);

You can use the Array#some method and check if at least one element is undefined
const isAlertMissing = (array) => array.some(elem => elem.alert === undefined)
const objs1 = [{alert: "foo"},{alert: "foo"},{}]
const objs2 = [{alert: "foo"},{alert: "foo"}]
console.log(isAlertMissing(objs1))
console.log(isAlertMissing(objs2))

You can use every to check all items and some with Object.keys for finding a key in the inner objects.
const data = [{alert:"hi"},{alert:"bye"},{}]
const result = data.every(item => Object.keys(item).some(key => key === "alert"));
console.log(result) //false
EDIT
some with Object.keys is kind of roundabout, so we can use hasOwnProperty instead.
const data = [{alert:"hi"},{alert:"bye"},{}]
const result = data.every(item => item.hasOwnProperty("alert"));
console.log(result) //false

Array#some will succeed as soon a match is found, making it more efficient than Array#every.
const test = (data, propName) =>
!(data.some((el) => !el.hasOwnProperty(propName)))
const data1 = [ {alert:'hi'}, {alert:'bye'}, {}]
const data2 = [ {alert:'hi'}, {alert:'bye'}]
console.log(test(data1, 'alert')) // false
console.log(test(data2, 'alert')) // true
Or:
const test = (data, propName) => {
for(let el of data) {
if(!el.hasOwnProperty(propName))
return false
}
return true
}
const data1 = [ {alert:'hi'}, {alert:'bye'}, {}]
const data2 = [ {alert:'hi'}, {alert:'bye'}]
console.log(test(data1, 'alert')) // false
console.log(test(data2, 'alert')) // true

Related

Javascript Function: Use Variable instead of single Values

I found here a script. It works fine. But now, I want to use a Variable instead of single values.
Here the original script:
const customData = {
"func":"bri",
"oid":"ID",
"onVal":1,
"offVal":0,
"...":"..."
}
const getSubset = (obj, ...keys) => keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});
const Light.bri = getSubset(customData, "oid", "onVal", "offVal");
Result (OK):
bri: {
offVal: 0,
oid: "objekt-ID",
onVal: 1
},
Now I want to do define the keys in a variable, ideally as a object. But this do not work.
const params = {bri: "oid, onVal, offVal"};
const Light.bri = getSubset(customData, params.bri);
Result (NOK):
bri: {
oid, onVal, offVal: undefined
},
description: "Deckenspots"
}
what changes do I have to make?
Define the bri property as an array of strings. That way you can use the spread syntax (...) to pass the strings as individual arguments.
const params = {bri: ["oid", "onVal", "offVal"]}; // bri is now an array.
const Light.bri = getSubset(customData, ...params.bri); // Notice the ... before params.bri

Object destructuring with logical NOT all elements

I have an object:
const hide_account_settings_tabs = {
'links' :true,
'media' :true,
'status':true,
}
In another file I receive the object and assign every value + logical NOT on each element.
let showLinks = !hide_account_settings_tabs['links'];
let showMedia = !hide_account_settings_tabs['media'];
let showStatus = !hide_account_settings_tabs['status'];
Looking for a nice way to replace the 3 lines above with object destructuring. is this possible?
Something like:
let { showLinks, showMedia, showStatus} = !hide_account_settings_tabs;
You can use Object.keys or Object.values but you can maybe face problems if order is not conserved
const hide_account_settings_tabs = {
'links' :true,
'media' :true,
'status':true,
}
let [ showLinks, showMedia, showStatus ] = Object.keys(hide_account_settings_tabs)
.map(elem =>!hide_account_settings_tabs[elem]);
console.log( showLinks, showMedia, showStatus )
const hide_account_settings_tabs = {
'links' :true,
'media' :true,
'status':true,
}
let [ showLinks, showMedia, showStatus ] = Object.values(hide_account_settings_tabs)
.map(elem =>!elem);
console.log( showLinks, showMedia, showStatus )
You can use Object.entries to convert your object into an array of key-value pairs, then update the keys and invert the value. Then use Object.fromEntries to create a new object you then finally can destructure. This approach does not depend on any particular order of properties.
const { showlinks, showmedia, showstatus } = Object.fromEntries(
Object.entries(hide_account_settings_tabs).map(e => [`show${e[0]}`, !e[1]]));
Does it provide the required functionality? Yes. Is it elegant? IMHO, no ...

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.

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
}
})

Set First Value as Key in Javascript Array

Creating an array based off selected DataTables Rows
$('#savenlp').click(recordjourney);
function recordjourney() {
var data = table.rows(['.selected']).data().toArray();
console.log( (data) );
console.log( JSON.stringify(data) );
}
data returns
0 : (8) ["Which", "TitleCase", "QuestionWord", "", "", "", "", ""]
JSON.stringify(data) returns
[["baseball","Noun","Singular","","","","",""]]
This information is dynamically generated, so I am just looking to take the first value (in this case baseball) and turn it into something like
"baseball": [
"Noun",
"Singular"
]
I can return the first value (the key I want using)
alert(data[0][0]);
I am much more adept in PHP but I am learning javascript/jquery more and more.
It is my understanding javascript does not have associative arrays, so I am a bit confused as to how to generate this.
const data = [
["baseball","Noun","Singular","","","","",""],
["baseballs","Noun","","Plural","","","","",]
];
const mappedData = data.reduce((acc, row) => { acc[row.shift()] = row.filter(d => d !== ''); return acc; }, {});
console.log(mappedData);
We can use object destructuring and spread operators for ease of use.
In the example below, the key will be the first item and all the rest items will be placed in the newData variable
const data = [["baseball","Noun","Singular","","","","",""]];
const [key, ...newData] = data[0]
// if you want the new data to not have empty entries, simple apply the filter
const newDataFiltered = newData.filter(item => !!item)
const objWithEmpty = {[key]: newData}
const objWithoutEmpty = {[key]: newDataFiltered}
console.log(objWithEmpty, objWithoutEmpty)
For multiple arrays inside the outer array, just enclose the whole logic inside a for loop
const data = [
["baseball","Noun","Singular","","","","",""],
["baseball1","Noun1","Singular1","","","","",""],
["baseball2","Noun2","Singular2","","","","",""]
];
const objWithEmpty = {}
const objWithoutEmpty = {}
data.forEach((array) => {
const [key, ...newData] = array
// if you want the new data to not have empty entries, simple apply the filter
const newDataFiltered = newData.filter(item => !!item)
objWithEmpty[key] = newData
objWithoutEmpty[key] = newDataFiltered
})
console.log(objWithEmpty, objWithoutEmpty)
Simply extract the desired values from data and put them into an object formatted as you like:
const data = [["baseball","Noun","Singular","","","","",""]];
const firstArr = data[0];
const transformedFirstObject = {
[firstArr[0]]: [firstArr[1], firstArr[2]],
};
console.log(transformedFirstObject);
But it's pretty weird to have an object with only one property like that. If your data might have more than one sub-array in it and you want to turn the array of arrays into an array of objects, use map:
const data = [
["baseball","Noun","Singular","","","","",""],
["foo","bar","baz","","","","",""]
];
const transformed = Object.assign(...data.map(([prop, value1, value2]) => ({ [prop]: [value1, value2] })));
console.log(transformed);
A bit simpler compared to other answers here but works as well.
const data = [
["baseball","Noun","Singular","","","","",""],
["baseball1","Noun1","Singular1","","","","",""],
["baseball2","Noun2","Singular2","","","","",""]
];
const obj = [];
data.forEach(function(i) {
let jsonObj = {};
jsonObj [i[0]] = i.slice(1).filter(x=>x !='');
obj.push(jsonObj)
});
console.log(JSON.stringify(obj))
Just using forEach, considering multiple array elements.
var obj = {};
var arr = [
["baseball", "Noun", "Singular", "", "", "", "", ""],
["Test", "Test1", "Test2", "", "", "", "", ""]
];
arr.forEach(function(val, idx) {
val.forEach(function(val1, idx1) {
if (idx1 === 0) {
obj[val1] = val.slice(1, val.length)
}
})
})
console.log(JSON.stringify(obj))

Categories

Resources