I have written a function to search in a nested object. The problem is that it returns undefined instead of the expected result, that is correctly logged in the console. Whats going on there?
const in1 = [1, 2];
const in2 = [1, 2];
const vDOM = {
1: {
ref: in1,
children: {
2: {
ref: in2,
children: {}
}
}
}
}
const findVDOMNode = function(instance, vDOM) {
const keys = Object.keys(vDOM);
const foundKey = keys.find(key => vDOM[key].ref === instance);
//console.log(foundKey, vDOM, "FK");
if (!keys.length) {
console.log('no keys');
return;
}
if (foundKey) {
console.log('found', vDOM[foundKey]);
return true; //vDOM[foundKey];
};
keys.map(key =>
findVDOMNode(instance, vDOM[key].children));
}
console.log('res: ', findVDOMNode(in2, vDOM));
Live example: https://stackblitz.com/edit/js-dapzsy
Just add return at the end.
return keys.map(key =>
findVDOMNode(instance, vDOM[key].children));
You could take the values of the object and check it against the instance. If an object is found, check the object as well. For iterating use some with short circuit, if the instance is found.
const
in1 = [1, 2],
in2 = [1, 2],
vDOM = { 1: { ref: in1, children: { 2: { ref: in2, children: {} } } } },
findVDOMNode = (instance, vDOM) => Object
.values(vDOM)
.some(v => v === instance
|| v && typeof v === 'object' && findVDOMNode(instance, v)
);
console.log('res: ', findVDOMNode(in2, vDOM));
it looks like you are missing a return statement on the map in the last line of the function
const in1 = [1, 2];
const in2 = [1, 2];
const vDOM = {
1: {
ref: in1,
children: {
2: {
ref: in2,
children: {}
}
}
}
}
const findVDOMNode = function(instance, vDOM) {
const keys = Object.keys(vDOM);
const foundKey = keys.find(key => vDOM[key].ref === instance);
//console.log(foundKey, vDOM, "FK");
if (!keys.length) {
console.log('no keys');
return;
}
if (foundKey) {
console.log('found', vDOM[foundKey]);
return true; //vDOM[foundKey];
};
///added this return statement
return keys.map(key =>
findVDOMNode(instance, vDOM[key].children));
}
console.log('res: ', findVDOMNode(in2, vDOM));
Related
I have the following React code,
const useDynamicReplaceVariable = ({ label, formikValues, fieldsTypes }) => {
const { locale } = useTranslationState();
const formattedLabel = useMemo(() => {
const variablesRegex = /\?([\w-]+)\?/g;
let labelResult = label;
if (variablesRegex.test(label)) {
labelResult = ' ';
if (Object.keys(formikValues).length > 0) {
labelResult = label.replace(variablesRegex, (_, ...[variable]) => {
const type = fieldsTypes[variable];
// Set undefined or null to empty
let variableValue = (formikValues[variable] === undefined || formikValues[variable] == null) ? '' : formikValues[variable];
if (variableValue && [DesignerDdTypes.DatePicker, DesignerDdTypes.DatetimePicker].includes(type)) {
variableValue = dateToString(variableValue, locale, type === DesignerDdTypes.DatetimePicker);
}
return variableValue;
});
}
}
return labelResult;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [label, JSON.stringify(formikValues)]);
return { formattedLabel };
};
I can't understand the line labelResult = label.replace(variablesRegex, (_, ...[variable]), when no variable is defined, how come spread syntax is applied over it?
...[variable] is a shorthand for
function someFunction(...args) {
const [variable] = args
}
someFunction(1, 2, 3, 4, 5)
function someFunction(arg1, ...args) {
console.log('arg1', arg1)
console.log('args', args)
const [variable] = args
console.log('variable', variable)
}
someFunction(1, 2, 3, 4, 5)
function someFunction(arg1, ...[variable]) {
console.log('arg1', arg1)
console.log('variable', variable)
}
If this is my object
{
"a":{
"a1":5,
"b":{
"b1":10,
"b2":15,
"c":{
"c1":15
}
}
}
}
the output I want is:
{a:45 b:40, c: 15}
c => 15
b => 10 + 15 + c
a => 5 + b + c
how do I achieve this? been banging my head against a brick wall all day
so far I've tried:
let constructedTotals = {};
const calculateVals = (vals) => {
return vals
.map((val) => {
if (typeof val === "object" && Object.keys(val).length > 0) {
return Object.values(val);
}
return val;
})
.flatMap((x) => x)
.filter((x) => typeof x === "number")
.reduce((a, b) => a + b, 0);
};
const constructing = (construct) => {
return Object.entries(construct).map((entry) => {
if (typeof entry[1] === "object") {
constructing(entry[1]);
constructedTotals = {
...constructedTotals,
[entry[0]]: calculateVals(Object.values(entry[1])),
};
} else {
console.log('here')
}
});
};
const data = {
a: {
a1: 5,
b: {
b1: 10,
b2: 15,
c: {
c1: 15,
},
},
},
};
const outputObj = {};
function addValue(data) {
for (const [key, value] of Object.entries(data)) {
const outKey = key.at(0);
outputObj[outKey] ??= 0;
if (typeof value === "object") addValue(value);
else for (const svKey in outputObj) outputObj[svKey] += value;
}
}
addValue(data);
console.log(outputObj);
You could handover the parent key and add the total of nested keys.
const
sum = (object, parent = '') => Object
.entries(object)
.reduce((r, [k, v]) => {
if (v && typeof v === 'object') {
Object.assign(r, sum(v, k));
if (parent) r[parent] += r[k];
} else {
r[parent] = (r[parent] || 0) + v;
}
return r;
}, {}),
data = { a: { a1: 5, b: { b1: 10, b2: 15, c: { c1: 15 } } } },
result = sum(data);
console.log(result);
You could create a reducer function that:
Builds an object by key
Accumulates the total of the numbered keys for each node, and adds the previous total
const main = () => {
const result = reduce(tree, (acc, node) => {
let currKey, prevKey, currVal = 0;
for (const prop in node) {
const [, key] = prop.match(/^(\w)\d$/) ?? [];
currKey ??= key;
if (key) currVal += +node[prop];
prevKey ??= prop.match(/^(\w)$/)?.[1];
}
if (currKey) {
acc[currKey] = (acc[prevKey] ?? 0) + currVal;
}
});
console.log(result); // { "c": 15, "b": 40, "a": 45 }
};
const reduce = (node, visitor) => {
const result = {};
traverse(node, visitor, result);
return result;
};
const traverse = (node, visitor, result) => {
if (typeof node === 'object') {
for (const prop in node) {
traverse(node[prop], visitor, result);
}
}
visitor(result, node);
};
const tree = {
a: {
a1: 5,
b: {
b1: 10,
b2: 15,
c: {
c1: 15
}
}
}
};
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }
you can try this:
let obj = {
"a":{
"a1":5,
"b":{
"b1":10,
"b2":15,
"c":{
"c1":15
}
}
}
}
let recusive = (obj,output)=>{
if(typeof(obj) == "object"){
let keys = Object.keys(obj)
let sum = 0;
keys.forEach(key => {
if(typeof(obj[key]) == "object"){
output[key] = recusive(obj[key],output)
sum += output[key]
}
else
sum+= obj[key]
});
return sum
}
else
return obj;
}
let warp = (obj) => {
let output = {};
recusive(obj, output);
return output;
}
console.log(warp(obj))
The output will hold the result, it worked for the example you gave, might throw if you give it an object that is build differently
I have an array of object from which I am trying to get values using map operator but I am getting the whole json objects all I want is just array of values.
Below is my code:
const obj = [
{
a: {
b: 'Paul',
}
},
{
c: 'Byeeee',
}
];
obj.map((val) => console.log(val));
what I am getting is
{ a: { b: 'Paul' } }
{ c: 'Byeeee' }
What I want is:
['Paul','Byeeee']
Someone let me know how can I get the desired output.
You can do this recursively. You can first start off by grabbing the values of your object, and then loop through those using .flatMap(). If you encounter a value that is an object, you can recursively grab the values of that object by recalling your function. Otherwise, you can return the value. The advantage of using .flatMap() here is that when the recursive call returns an array, we don't end up with inner arrays, but rather the array gets flattened into one resulting array:
const obj = [{ a: { b: 'Paul', } }, { c: 'Byeeee', } ];
const getValues = (obj) => {
return Object.values(obj).flatMap(val => Object(val) === val ? getValues(val) : val);
}
console.log(getValues(obj));
you can use the following solution.
const data = [{ a: { b: 'Paul' } }, { c: 'Byeeee' }];
const flatObjectValues = (obj, result) => {
// recursive function to get object values
const objValues = Object.values(obj);
if (objValues?.length > 0) {
objValues.map((v) => {
if (typeof v === 'object' && !Array.isArray(v)) {
flatObjectValues(v, result);
} else {
result.push(v);
}
return v;
});
}
};
const updatedData = [];
data.map((x) => flatObjectValues(x, updatedData));
console.log('updatedData: ', updatedData);
You can use recursion with array.reduce, like fellowing.
function getAllValues(objuct) {
return objuct.reduce((acc, curr) => {
if (typeof curr === 'object') {
return [...acc, ...getAllValues(Object.values(curr))];
}
return [...acc, curr];
}, []);
}
A recursive solution could be:
const arr = [{a: {b: "Paul",},},{c: "Byeeee",},];
const flatArrOfObjects = (arr) => {
const values = [];
for (const i in arr) flatObj(arr[i], values);
return values;
};
const flatObj = (obj, result) => {
for (const [key, value] of Object.entries(obj)) {
if (typeof value === "object") flatObj(value, result);
else result.push(value);
}
};
console.log(flatArrOfObjects(arr));
I am using React. On click of a button, the following function is executed:
const completeTaskHandler = (idValue) => {
setData((prevData) => {
const updatedData = [...prevData];
const updatedItem = updatedData.filter((ele) => ele.id === idValue)[0];
updatedItem.completed = true;
const newData = updatedData.filter((ele) => ele !== updatedItem);
newData.unshift(updatedItem);
return newData;
});
};
My data is an array of objects like this:
[{userId: 1, id: 2, title: "task 1", completed: true}, .....].
Basically I want to move the updated item to the start of the array. Is there any better solution for this?
updatedItem should not be mutated. And this string const newData = updatedData.filter((ele) => ele !== updatedItem); is not fine. You can do it like this :
const completeTaskHandler = (idValue) => {
setData((prevData) => {
const targetItem = prevData.find((ele) => ele.id === idValue);
const updatedItem = { ...targetItem, completed: true };
const filteredData = prevData.filter((ele) => ele.id !== idValue);
return [updatedItem, ...filteredData];
});
};
Even better to reducing an extra filter:
const completeTaskHandler = (idValue) => {
setData((prevData) => {
const targetIndex = prevData.findIndex((ele) => ele.id === idValue);
return [{ ...prevData[targetIndex], completed: true }].concat(prevData.slice(0, targetIndex + 1)) .concat(
prevData.slice(targetIndex + 1)
)
});
};
First find index of updated element using Array.findIndex(), then remove the same element using Array.splice() and add it to front of the array.
const completeTaskHandler = (idValue) => {
setData((prevData) => {
const updatedData = [...prevData];
const index = updatedData.findIndex(obj => obj.id === idValue);
const [updatedItem] = updatedData.splice(index, 1);
updatedItem.completed = true;
updatedData.unshift(updatedItem);
return updatedData;
});
};
The simplest one with only one forEach.
const completeTaskHandler = idValue => {
setData(prevData => {
let updatedItem = {}, newData = [];
prevData.forEach((ele) => {
if (ele.id === idValue) {
updatedItem = ele;
updatedItem.completed = true;
} else {
newData.push(ele);
}
});
newData.unshift(updatedItem);
return newData;
});
};
I want to check the value of every key in each object and write its length.
I tried doing this:
const a = [
{
name:"Bill",
age:'',
old:''
}
]
const myF = (arr) => {
return arr.map((i,k) => {
console.log(Object.keys(i))
return{ [Object.keys(i)]: ''}
})
}
console.log(myF(a))
I expect to get:
{
name:4,
age:0,
old:0
}
You can map it by taking entries. Let me know if this is what something you need:
var a = [ { name:"Bill", age:'', old:''}];
var result = a.map(obj=>Object.fromEntries(Object.entries(obj).map(([k,v])=>[k, v ? v : v.length])));
var result2 = a.map(obj=>Object.fromEntries(Object.entries(obj).map(([k,v])=>[k, v.length])));
console.log(result);
console.log(result2)
const a = [
{
name:"Bill",
age:'',
old:''
}
]
var b = a.map((x) =>{
if(x.age == '') {
x.age = 0;
}
if(x.old == '') {
x.old = 0;
}
return x;
})
console.log(b)