Map the object using javascript and get expected structure object - javascript

I want to map below mentioned object...
Input object:
const rules = {
public: [
{ label: 'View', value: 'View' },
{ label: 'Create', value: 'Create' },
{ label: 'Delete', value: 'Delete' },
{ label: 'Update', value: 'Update' },
{ label: 'ChangeLayout', value: 'ChangeLayout' }
],
user: [
{ label: 'View', value: 'View' },
{ label: 'Create', value: 'Create' },
{ label: 'Delete', value: 'Delete' },
{ label: 'Update', value: 'Update' },
{ label: 'ChangeLayout', value: 'ChangeLayout' }
]
};
Expected output is:
const result = {
Public: { "View": true, "Create": false, "Delete": false, "Update": false, "ChangeLayout": false },
User: { "View": true, "Create": true, "Delete": true, "Update": true, "ChangeLayout": true }
};
Actually i try some method but cant getting expected output
Thanks to advance please help anyone...

Please try to use below code
const rules = [
{ label: 'View', value: 'View' },
{ label: 'Create', value: 'Create' },
{ label: 'Delete', value: 'Delete' },
{ label: 'Update', value: 'Update' }
];
let outPut = {};
rules.forEach(item => {
outPut[item.value] = true;
})
console.log(outPut);

Your callback function is just returning a string, so map() is creating an array of strings, not an object.
The callback function should return an array containing the key and value. Then you can use Object.fromEntries() to turn that into the desired object.
const rules = {
public: [
{ label: 'View', value: 'View' },
{ label: 'Create', value: 'Create' },
{ label: 'Delete', value: 'Delete' },
{ label: 'Update', value: 'Update' },
{ label: 'ChangeLayout', value: 'ChangeLayout' }
],
user: [
{ label: 'View', value: 'View' },
{ label: 'Create', value: 'Create' },
{ label: 'Delete', value: 'Delete' },
{ label: 'Update', value: 'Update' },
{ label: 'ChangeLayout', value: 'ChangeLayout' }
]
};
const test = Object.fromEntries(Object.entries(rules).map(
([owner, rules]) => [owner, Object.fromEntries(
rules.map(rule => [rule.value, true]))]));
console.log(test);

To create a single object from your array, you can use a reduce operation, assigning the resulting key name via computed property names.
const rules = [{"label":"View","value":"View"},{"label":"Create","value":"Create"},{"label":"Delete","value":"Delete"},{"label":"Update","value":"Update"}]
const keyFrom = "value"
const t0 = performance.now()
const result = rules.reduce((obj, rule) => ({
...obj,
[rule[keyFrom]]: true
}), {})
const t1 = performance.now()
console.log(result)
console.log(`Operation took ${t1 - t0}ms`)
I wasn't sure which property should provide the key name in your final object so I made it configurable via the keyFrom variable.

Related

Antd Tree, : how to Disable checking child by default

I working on a react project using Antd and I want to be able to disable cheking childs of my Tree component, so I can check only parent.This is my code
I found that I can add checkable : false to my child but I must create a function that render me a new TreeData that I can use instead of my normal data so I've tried this :
const TreeData = (data) => {
data.map((category) => {
category.children.map((family) => {
family.children.map((table) => {
table.checkable = false;
});
});
});
};
But it return undefined when i'm console.log the data received..
So my question is : how to switch from this :
const treeData = [
{
title: "0-0",
key: "0-0",
children: [
{
title: "0-0-0",
key: "0-0-0",
children: [
{
title: "0-0-0-0",
key: "0-0-0-0"
},
{
title: "0-0-0-1",
key: "0-0-0-1"
},
{
title: "0-0-0-2",
key: "0-0-0-2"
}
]
},
{
title: "0-0-1",
key: "0-0-1",
children: [
{
title: "0-0-1-0",
key: "0-0-1-0"
},
{
title: "0-0-1-1",
key: "0-0-1-1"
},
{
title: "0-0-1-2",
key: "0-0-1-2"
}
]
},
{
title: "0-0-2",
key: "0-0-2"
}
]
},
{
title: "0-1",
key: "0-1",
children: [
{
title: "0-1-0-0",
key: "0-1-0-0"
},
{
title: "0-1-0-1",
key: "0-1-0-1"
},
{
title: "0-1-0-2",
key: "0-1-0-2"
}
]
},
{
title: "0-2",
key: "0-2"
}
];
To this :
const treeData = [
{
title: "0-0",
key: "0-0",
children: [
{
checkable: false,
title: "0-0-0",
key: "0-0-0",
children: [
{
title: "0-0-0-0",
key: "0-0-0-0"
},
{
title: "0-0-0-1",
key: "0-0-0-1"
},
{
title: "0-0-0-2",
key: "0-0-0-2"
}
]
},
{
checkable: false,
title: "0-0-1",
key: "0-0-1",
children: [
{
title: "0-0-1-0",
key: "0-0-1-0"
},
{
title: "0-0-1-1",
key: "0-0-1-1"
},
{
title: "0-0-1-2",
key: "0-0-1-2"
}
]
},
{
checkable: false,
title: "0-0-2",
key: "0-0-2"
}
]
},
{
title: "0-1",
key: "0-1",
children: [
{
checkable: false,
title: "0-1-0-0",
key: "0-1-0-0"
},
{
checkable: false,
title: "0-1-0-1",
key: "0-1-0-1"
},
{
checkable: false,
title: "0-1-0-2",
key: "0-1-0-2"
}
]
},
{
title: "0-2",
key: "0-2"
}
];
Without hardchanging the first data of my Tree.
Thank you
This may be one possible implementation to set checkable as false for the specific nodes described in this question:
const makeUnCheckable = dataArr => (
dataArr.map(
obj => ({
...obj,
children: obj?.children?.map(cObj => ({
...cObj,
checkable: false
}))
})
)
);
return (
<Tree
checkable
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
onCheck={onCheck}
checkedKeys={checkedKeys}
onSelect={onSelect}
selectedKeys={selectedKeys}
treeData={makeUnCheckable(treeData)}
/>
);
This is the result displayed on Codesandbox:
NOTES:
The elements showing as checked are clicked manually.
There is no check option for nodes 0-0-0, 0-0-1, 0-0-2, 0-1-0-0, 0-1-0-1, 0-1-0-2 - which is the expected objective defined in the question under To this
EDITED:
On perusing this previous question it seems like OP requires something like this:
(A tree where leaf nodes are uncheckable)
This may be achieved by a recursive method - something like this:
(Changes are present in: Lines 100 to 106. And line 118.)
EDITED - 2
Update based on comments below.
In order to identify the children for any given parent/key, something like the below may be useful:
Two methods are here. One is findKey which is recursive and gets the object which has a particular key (say 0-0-1). The other is to check if the object with the key has any children and if yes, return the children array.

Combine array of objects into a single object with a nested object

I'm trying to turn this data
[
{
key: 'myvar',
value: 'my value',
global: false,
},
{
key: 'foo',
value: 'bar',
global: false,
},
{
key: 'featureEnabled',
value: true,
global: true,
accountId: 123,
},
]
into this
{
myvar: 'my value'
foo: 'bar'
123: { 'featureEnabled': true }
}
I was thinking something along the lines of something like below but this will return undefined for objects that don't have an accountId property. I thought there might be a way to use an if statement here.
const globalResponse = Object.assign({}, ...getPreference.map(o => ({ [o.accountId]: { [o.key]: o.value } })))
You can use of reduce to build your new object and setup specific triggers for specifics use cases.
function mutateObject(tmpBasis, key, value) {
tmpBasis[key] = value;
return tmpBasis;
}
const ret = [{
key: 'myvar',
value: 'my value',
global: false,
},
{
key: 'foo',
value: 'bar',
global: false,
},
{
key: 'featureEnabled',
value: true,
global: true,
accountId: 123,
},
{
key: 'otherKey',
value: true,
global: true,
accountId: 123,
},
{
key: 'featureEnabled',
value: true,
global: true,
accountId: 512,
},
].reduce((tmp, {
key,
value,
global,
accountId,
}) => ({
...tmp,
// If we are in global case, we either create an empty object containing the new key
// or we add the new key inside of the existing object
[global ? accountId : key]: global ? mutateObject(tmp[accountId] || {}, key, value) : value,
}), {});
console.log(ret);
You can use reduce() with a condition inside like below
var myJSON = [{
key: 'myvar',
value: 'my value',
global: false,
},
{
key: 'foo',
value: 'bar',
global: false,
},
{
key: 'featureEnabled',
value: true,
global: true,
accountId: 123,
},
];
let newJSON = myJSON.reduce((target, item) => {
!!item.accountId ? target[item.accountId] = { [item.key]: item.value } : target[item.key] = item.value;
return target;
}, {});
console.log(newJSON);

How to find the first property that is an array in an object?

I'm creating a function that loops through an array like this:
schema: [{
name: 'firstRow',
fields: [{
name: 'name',
text: 'Name',
type: 'text',
col: 12,
value: ''
}]
}, {
And returns a callback with the values of the objects:
eachDeep (array, callback) {
array.forEach(item => {
item.fields.forEach(field => {
callback(field)
})
})
},
As you can see the item.fields.forEach part is harcoded. How can I modify the function so it detects the first property that it's an array and loop through it? (e.g. in this case that property is fields).
To find whether a property of an object is an array or not you can also use this one:
//let item be your object's property
if(typeof item == "object" && item.length > 0){
//do whatever if it is an array
}
You can check if the field is not an array or not, if so loop it, otherwise do something else with it.
var data = [{
name: 'firstRow',
fields: [{
name: 'name',
text: 'Name',
type: 'text',
col: 12,
value: ''
}]
}, {
name: 'firstRow',
fields: [{
name: 'name',
text: 'Name',
type: 'text',
col: 12,
value: ''
}]
}];
eachDeep (array, callback) {
array.forEach(item => {
// loop through each property again
item.forEach(prop => {
// if property is an array
if (prop instanceof Array) {
prop.forEach(field => callback(field));
} else {
// property is not an array
// do something else
}
})
})
},
var big_array =
[
{
name: 'firstRow',
fields: [{
name: 'name',
text: 'Name',
type: 'text',
col: 12,
value: ''
}]
}
];
for (let item of big_array)
{
for (let key in item)
{
if (Array.isArray(item[key]) )
{
console.log('this is an array do something:', key);
}
}
}
You could check using Array.isArray()
If the goal is to find the first array property you can do the following. Using ES6.
const schema = [{
name: 'firstRow',
fields: [{
name: 'name',
text: 'Name',
type: 'text',
col: 12,
value: ''
}]
}]
let firstArr;
schema.forEach(item => {
firstArr = Object.keys(item).filter(k => Array.isArray(item[k]))[0];
})

How to delete particular nodes within a nested object tree in JavaScript

Here is where my algorithm skills ends. I can traverse through the object and find a certain object but I'm not able to delete the object in the same time.
Here is the object
const obj = {
children: [{
children: [
{
children: [
{
key: 'a1',
type: 'a1_type'
},
{
key: 'a2',
type: 'a2_type'
}
],
key: 'root',
type: 'root_type'
},
{
key: 'error',
type: 'error_type'
}
]
}]
}
The object with the key === 'error' object can be in any children array. I want to find it and delete the object that contains the key.
The output should be like that:
let output = findAndDeleteObjByKeyAndType('error', 'error_type')
output = {
children: [{
children: [
{
children: [
{
key: 'a1',
type: 'a1_type'
},
{
key: 'a2',
type: 'a2_type'
}
],
key: 'root',
type: 'root_type'
}
]
}]
}
Can someone help here?
Array methods like filter and every can come in handy here:
const object = {
children: [{
children: [{
children: [{
key: 'a1',
type: 'a1_type'
},
{
key: 'a2',
type: 'a2_type'
},
{
key: 'error',
type: 'error_type'
}
],
key: 'root',
type: 'root_type'
},
{
key: 'error',
type: 'error_type'
}
]
}]
}
function purgeAll (object, target) {
if (object.children) {
const keys = Object.keys(target)
object.children = object.children.filter(o =>
!keys.every(k => target[k] === o[k]) && purgeAll(o, target)
)
}
return object
}
let output = purgeAll(object, {
key: 'error',
type: 'error_type'
})
console.log(output)
.as-console-wrapper { min-height: 100%; }

Concat array from Object from Array

I'm currently trying to retrieve a list of metadata stored as an array, inside an object, inside an array. Here's a better explanatory example:
[
{
name: 'test',
metadata: [
{
name: 'Author',
value: 'foo'
},
{
name: 'Creator',
value: 'foo'
}
]
},
{
name: 'otherTest',
metadata: [
{
name: 'Created',
value: 'foo'
},
{
name: 'Date',
value: 'foo'
}
]
},
{
name: 'finalTest'
}
]
Now, my objective is to retrieve a list of metadata (by their name) without redundancy. I think that .map() is the key to success but I can't find how to do it in a short way, actually my code is composed 2 for and 3 if, and I feel dirty to do that.
The expected input is: ['Author', 'Creator', 'Created', 'Date']
I'm developping in Typescript, if that can help for some function.
You can use reduce() and then map() to return array of names.
var data = [{"name":"test","metadata":[{"name":"Author","value":"foo"},{"name":"Creator","value":"foo"}]},{"name":"otherTest","metadata":[{"name":"Created","value":"foo"},{"name":"Date","value":"foo"}]},{"name":"finalTest"}]
var result = [...new Set(data.reduce(function(r, o) {
if (o.metadata) r = r.concat(o.metadata.map(e => e.name))
return r
}, []))];
console.log(result)
You could use Set for unique names.
var data = [{ name: 'test', metadata: [{ name: 'Author', value: 'foo' }, { name: 'Creator', value: 'foo' }] }, { name: 'otherTest', metadata: [{ name: 'Created', value: 'foo' }, { name: 'Date', value: 'foo' }] }, { name: 'finalTest' }],
names = new Set;
data.forEach(a => (a.metadata || []).forEach(m => names.add(m.name)));
console.log([...names]);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var data = [{"name":"test","metadata":[{"name":"Author","value":"foo"},{"name":"Creator","value":"foo"}]},{"name":"otherTest","metadata":[{"name":"Created","value":"foo"},{"name":"Date","value":"foo"}]},{"name":"finalTest"}]
data
.filter(function(obj){return obj.metadata != undefined})
.map(function(obj){return obj.metadata})
.reduce(function(a,b){return a.concat(b)},[])
.map(function(obj){return obj.name})
A hand to hand Array.prototype.reduce() and Array.prototype.map() should do it as follows;
var arr = [
{
name: 'test',
metadata: [
{
name: 'Author',
value: 'foo'
},
{
name: 'Creator',
value: 'foo'
}
]
},
{
name: 'otherTest',
metadata: [
{
name: 'Created',
value: 'foo'
},
{
name: 'Date',
value: 'foo'
}
]
},
{
name: 'finalTest'
}
];
result = arr.reduce((p,c) => c.metadata ? p.concat(c.metadata.map(e => e.name))
: p, []);
console.log(result);

Categories

Resources