Building adjacency matrix from an array of objects - javascript

I have a plain JavaScript array of objects, say e.g.
const drawings = [
{
name: "Foo",
category: "widget"
},
{
name: "Bar",
category: "widget"
},
{
name: "Bar",
category: "fidget"
},
]
etc, where both the name and category have duplicates. What I want to end up with is essentially a list of objects (this is to meet the interface for a 3rd party library), where each object represents a name, and then for each category there is a property that is either true or false, depending on the original list. So for the example the output would be:
const output = [
{
name: "Foo",
widget: true,
fidget: false
},
{
{
name: "Bar",
widget: true,
fidget: true
},
]

I would first go through and make an object of your categories with the categories as keys and default values as false.
Then you can assign this to each object and set the correct keys to true as you go through.
const drawings = [{name: "Foo",category: "widget"},{name: "Bar",category: "widget"},{name: "Bar",category: "fidget"},]
// make category object where everything is false
let category_obj = drawings.reduce((a, item) => (a[item.category] = false, a), {})
let output = drawings.reduce((a, {name, category}) => {
// assign cat
if (!a.hasOwnProperty(name)) a[name] = Object.assign({}, {name}, category_obj)
// set to true if the correct category
a[name][category] = true
return a
}, {})
// the above makes an object, but you only want the array of values
console.log(Object.values(output))

If you already know the categories or if you have infered them as you suggested, you could use Array.reduce() like such:
drawings.reduce(function(acc, curr) {
if (!acc.some(elt => elt.name === curr.name)) {
acc.push({name: curr.name, widget: false, fidget: false})
}
const i = acc.findIndex(elt => elt.name === curr.name)
acc[i][curr.category] = true
return acc
}, [])

Related

How to get only true value key pair from array of objects

I have an array of object that is coming from some api.The data i am getting is like this. It has multiple values but i only want to show the user which access he has. Suppose a user have only read access so i want to show the user read key.
[
{
admin: false,
createdAt: "2022-08-21T05:32:20.936Z",
id: 8,
read: false,
write: true,
},
];
So, i want to get only the key value pair from this array which has true values so i can show the keys using Object.keys().
expected result
[{write:true}]
I have tried different array methods but didn't succeed, here how i was thinking to solve this problem but it's only returning last element value.
item.map(tab => {
return Object.keys(tab).reduce((acc: string, key) => {
if (tab[key]) {
acc[key] = tab[key];
}
return acc;
}, {});
}),
You can get rid of reduce by creating an object from filtered entries. Then just filter by true values.
data = [
{
admin: false,
createdAt: "2022-08-21T05:32:20.936Z",
id: 8,
read: false,
write: true,
},
{
admin: false,
createdAt: "1234",
id: 8,
read: true,
write: true,
}
];
out = data.map(item => Object.fromEntries(Object.entries(item).filter(([key, value]) => value === true)));
console.log(out)
if (tab[key]) will be applied on any truthy value not just true, for example, not empty string is a truthy value, any number is a truthy value except zero.
So you need explicitly check if the value equal to true by if (tab[key] === true)
const data = [
{
admin: false,
createdAt: "2022-08-21T05:32:20.936Z",
id: 8,
read: false,
write: true,
},
];
const result = data.map(tab => {
return Object.keys(tab).reduce((acc, key) => {
if (tab[key] === true) {
acc[key] = tab[key];
}
return acc;
}, {});
})
console.log(result)
For shorthand use can use
const result = data.map(tab => Object.entries(tab).reduce((acc, [key, value]) => ({ ...acc, ...(value === true && { [key]: value }) }), {}));
You can get the keys you want by changing the 2nd parameter of the keyFilters function.
let tabs = [
{admin: false,createdAt: "2022-08-21T05:32:20.936Z",id: 8,read: false,write: true},
{admin: false,createdAt: "2022-08-21T05:32:20.936Z",id: 8,read: true,write: true}
];
let keyFilters = function(values, keys){
let filteredKeys = {}
Object.keys(values).map((key, index)=>{
if (keys.includes(key)){
filteredKeys[key] = values[key]
}
})
return filteredKeys;
}
let filters = tabs.map(tab=>keyFilters(tab, ["read", "write"]))
console.log(filters)
output
0:(2) {read: false, write: true}
1:(2) {read: true, write: true

Filter array object by array of Boolean values dynamically

I have my array object in the following format
menuItem = [{
"name": "MOZZARELLA DI BUFALA & TOMATOES",
"gluten": true,
"eggs": false,
"dairy": true,
...
},...
I want to filter hundreds of menuItems by the allergen values (Boolean).
While the following code does the trick:
menuItem.filter(el => !el.gluten && !el.fish && !el.soy && !el.dairy)"
The allergens are hardcoded and repetitive. I am struggling to make the code dynamic and elegant.
I tried the following solution
menuItem.filter(el => !el[allergens])"
var allergens = ['gluten', 'fish', 'soy', 'dairy']
However, it only works correctly with one allergen value. Multiple values as in the above example do not filter anything.
You could use .some or .every, whichever match your case
const allergens = ['gluten', 'fish', 'soy', 'dairy']
const res = menuItem.filter(
(el) => !allergens.every((allergen) => el[allergen])
);
// equivalent to `menuItem.filter(el => !el.gluten && !el.fish && !el.soy && !el.dairy)`
const menuItem = [
{
name: 'dish A',
gluten: true,
fish: true,
soy: true,
dairy: true,
},
{
name: 'dish B',
gluten: true,
fish: true,
soy: false,
dairy: true,
},
];
const allergens = ['gluten', 'fish', 'soy', 'dairy'];
const res = menuItem.filter(
(el) => !allergens.every((allergen) => el[allergen])
);
console.log(res);
First extract the name property, then check that the rest of the properties in the object are falsey.
menuItem.filter(
({ name, ...rest }) => Object.values(rest).every(val => !val)
);
Ideally, I'd prefer to restructure the input array so the allergies are in a separate property, perhaps:
menuItem = [{
"name": "MOZZARELLA DI BUFALA & TOMATOES",
allergens: {
"gluten": true,
"eggs": false,
"dairy": true,
to make accessing them easier.
menuItem.filter(
({ allergens }) => Object.values(allergens).every(val => !val)
);

Using reduce on an object with an array

I have this JavaScript object
{
names: [ "youtube","twitch"],
autoEnable: true
}
I want to convert this object into an array of objects for every name I have in my array. autoEnable and isEnabled correspond
[{
name: youtube,
isEnabled: true
},
{
name: twitch,
isEnabled: true
}]
This isn't a use case for reduce (outside of functional programming with prebuilt, reusable reducers, almost nothing is, though it's often used anyway); it's a case for map:
const obj = {
names: [ "youtube","twitch"],
autoEnable: true
};
const array = obj.names.map(name => ({name, views: 46, isEnabled: obj.autoEnable}));
Live Example:
const obj = {
names: [ "youtube","twitch"],
autoEnable: true
};
const array = obj.names.map(name => ({name, views: 46, isEnabled: obj.autoEnable}));
console.log(array);
const data = {
names: [ "youtube","twitch"],
autoEnable: true
}
const a = data.names.map((name) => {
return {
name,
isEnabled: true, // you could run a function here to get this value
views: 46 // you could run a function here to get this value
}
});
console.log(a);

Sort an array of objects dynamically javascript

I am having an array with the below items. I need to sort the below array to the array that is shown in sorted items,so that all the value with the rules can be together and the ELIG_DATABASE should be grouped with the ELIG_SERVICE.
const items =[{"name":"ELIG_DATABASE","ready":true},
{"name":"ELIG_RULES_SERVICE","ready":true},
{"name":"ELIG_GATEWAY","ready":true},
{"name":"ELIG_GATEWAY_LATEST","ready":true,"latest":true},
{"name":"ELIG_SERVICE_LATEST","ready":true,"latest":true},
{"name":"ELIG_SERVICE","ready":true},
{"name":"HDXTS","ready":false},
{"name":"RULES_VERSION","ready":true},];
I want to achieve this array so that values in the name property that has rules can be together,gateway things should be together, elig service thing should be together just that ELIG_DATABASE should be grouped together with elig service and then all other values in the name property can be sorted alphabetically.
const sortedItems =[
{"name":"ELIG_GATEWAY","ready":true},
{"name":"ELIG_GATEWAY_LATEST","ready":true,"latest":true},
{"name":"ELIG_RULES_SERVICE","ready":true},
{"name":"RULES_VERSION","ready":true},
{"name":"ELIG_DATABASE","ready":true},
{"name":"ELIG_SERVICE_LATEST","ready":true,"latest":true},
{"name":"ELIG_SERVICE","ready":true},
{"name":"HDXTS","ready":false}
];
I tried using this code but that sorts alphabetically putting ELIG_DATABASE in first position.Could any one please help on how to achieve this array in minimum code as possible.
items.sort((svcA, svcB) => {
const serviceA = svcA.name.toUpperCase();
const serviceB = svcB.name.toUpperCase();
return serviceA.localeCompare(serviceB);
});
You could take the wanted groups first in an array, sort the data and assign the object to the group or to the end of a temp array and get the flat data as result.
var data = [{ name: "ELIG_DATABASE", ready: true }, { name: "ELIG_RULES_SERVICE", ready: true }, { name: "ELIG_GATEWAY", ready: true }, { name: "ELIG_GATEWAY_LATEST", ready: true, latest: true }, { name: "ELIG_SERVICE_LATEST", ready: true, latest: true }, { name: "ELIG_SERVICE", ready: true }, { name: "HDXTS", ready: false }, { name: "RULES_VERSION", ready: true }],
together = [['GATEWAY'], ['RULES'], ['ELIG_DATABASE', 'ELIG_SERVICE']],
groups = { GATEWAY: [], RULES: [], ELIG_DATABASE: [] },
temp = [groups.GATEWAY, groups.RULES, groups.ELIG_DATABASE],
result;
for (let o of data.sort(({ name: a }, { name: b }) => a.localeCompare(b))) {
let target = together.find(a => a.some(v => o.name.includes(v)));
if (target) groups[target[0]].push(o);
else temp.push(o);
}
result = temp.flat();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I need to get a value from an object inside an array

With Javascript how can I get the id of each object in this kind of object:
array = [
{ active: false, defaultTag:true, id: '507f191e810c19729de860ea', title: 'one' },
{ active: false, defaultTag:true, id: '507f191e810c19722de860ea', title: 'two' }
];
I need to fetch the id in order to check if the item already exists in the array whe a use intent to save the same object again.
Best regards
Americo
here you can get array of unique ids
var unique = [],
tmp, i = 0;
while(i < array.length){
unique.indexOf(tmp = array[i++].id) > -1 ? array.pop(i--) : unique.push(tmp)
}
console.log(unique);
Gather all your items under one object using Array.reduce. This will filter out duplicates
Use Object.values to get the values inside your object. The returned value is the filtered array
const array = [
{ active: false, defaultTag:true, id: '507f191e810c19729de860ea', title: 'duplicateOne' },
{ active: false, defaultTag:true, id: '507f191e810c19729de860ea', title: 'one' },
{ active: false, defaultTag:true, id: '507f191e810c19722de860ea', title: 'two' }
];
const removeDupsById = arr => Object.values(
arr.reduce((a, c) => ({...a, [c.id]: c}), {})
);
console.log(removeDupsById(array));

Categories