Consider the following object:
{
"params": {
"time_to_diagnosis": [
{
"field": "date_of_diagnosis",
"value": ""
},
{
"field": "date_of_symptom_onset",
"value": "2019-09-01"
}
],
"time_since_onset": [
{
"field": "date_of_symptom_onset",
"value": "2019-09-01"
}
]
}
}
As you can tell this is a object , of objects with arrays that them selves contains objects.
As you can see some keys are empty.
The idea is that if there are no empty keys in the arrays containing objects, then return true, else return false.
Heres what I wrote:
const isParamsInAjaxParamsEmpty = (paramsForAjaxCall) => {
for (const key in paramsForAjaxCall) {
for (const nestedKey in paramsForAjaxCall[key]) {
const params = paramsForAjaxCall[key];
if (params[nestedKey] === "") {
return true;
}
}
}
return false;
}
I Know I can do an Array.isArray on the nestedKey part, but Im not sure how to make this recursive, as there could be one or more arrays.
paramsForAjaxCall is the object above.
Thoughts?
you can map the array then take the values from the Object and with every will get a boolean value so it's an array of booleans in the end because we mapping.
if this array contains a false so the result is false
const data = {
"params": {
"time_to_diagnosis": [{
"field": "date_of_diagnosis",
"value": "ddd"
},
{
"field": "date_of_symptom_onset",
"value": "2019-09-01"
}
],
"time_since_onset": [{
"field": "date_of_symptom_onset",
"value": "2019-09-01"
}]
}
}
const res = !Object.values(data).map(o => Object.values(o).map(value => value.every(({
value
}) => value !== ""))).flat().includes(false)
console.log(res)
You could take a check for not object and return false, then check for the wanted property or iterate all properties.
function check(object) {
if (!object || typeof object !== 'object') return false;
if (object.value) return true;
return Object.values(object).every(check);
}
var object = { params: { time_to_diagnosis: [{ field: "date_of_diagnosis", value: "" }, { field: "date_of_symptom_onset", value: "2019-09-01" }], time_since_onset: [{ field: "date_of_symptom_onset", value: "2019-09-01" }] } }
console.log(check(object));
object.params.time_to_diagnosis[0].value= "foo";
console.log(check(object));
Related
I saw many answers, but I haven't been able to modify any to my need.
Object
{
"id": "476ky1",
"custom_id": null,
"name": "Reunião com o novo Gerente de Vendas - Airton",
"text_content": null,
"description": null,
"status": {
"id": "p3203621_11svBhbO"
},
"archived": false,
"creator": {
"id": 3184709
},
"time_spent": 0,
"custom_fields": [{
"id": "36c0de9a-9243-4259-ba57-bd590ba07fe0",
"name": "Comments",
"value": "dsdsdsds"
}],
"attachments": []
}
Within custom_fields, if the property name's value is Comments, update the value property.
I've tried it like this, using this approach, for example, but it doesn't produce the expected result.
const updatedComment = [{ name: "Comments", value: "The comment is updated"}];
updateNestedObj(taskData, updatedComment)
function updateNestedObj(obj, updates) {
const updateToApply = updates.find(upd => upd.id === obj.id);
if (updateToApply) {
obj.title = updateToApply.content;
obj.note = updateToApply.note;
}
// Apply updates to any child objects
for(let k in obj) {
if (typeof(obj[k]) === 'object') {
updateNestedObj(obj[k], updates);
}
}
}
You're using the wrong property names when you search updates for updateToApply, and then when assigning the value.
When you recurse on children, you need to distinguish between arrays and ordinary objects, so you can loop over the nested arrays. You also have to skip null properties, because typeof null == 'object'.
const updatedComment = [{
name: "Comments",
value: "The comment is updated"
}];
function updateNestedObj(obj, updates) {
let updateToApply = updates.find(upd => upd.name == obj.name);
if (updateToApply) {
obj.value = updateToApply.value;
}
// Apply updates to any child objects
Object.values(obj).forEach(child => {
if (Array.isArray(child)) {
child.forEach(el => updateNestedObj(el, updates));
} else if (typeof(child) === 'object' && child != null) {
updateNestedObj(child, updates);
}
});
}
const taskData = {
"id": "476ky1",
"custom_id": null,
"name": "Reunião com o novo Gerente de Vendas - Airton",
"text_content": null,
"description": null,
"status": {
"id": "p3203621_11svBhbO"
},
"archived": false,
"creator": {
"id": 3184709
},
"time_spent": 0,
"custom_fields": [{
"id": "36c0de9a-9243-4259-ba57-bd590ba07fe0",
"name": "Comments",
"value": "dsdsdsds"
}],
"attachments": []
};
updateNestedObj(taskData, updatedComment)
console.log(taskData);
Try this:
const updatedComment = [{ name: "Comments", value: "A new comment value" }]
// you can add as many updates as you want
function update(obj, updates) {
for (const update in updates) {
for (const field in obj.custom_fields) {
if (obj.obj.custom_fields.name == update.name) {
obj.obj.custom_fields.value = update.value
}
}
}
}
update(obj, updatedComment)
this.StaticData = {
"values": [
{
"value": "test",
"label": "test"
},
{
"value": "aa",
"label": "bb"
},
{
"value": "cc",
"label": "dd"
}
]
};
I have above object of data. I wanted to return all object except currentIndex.
For example -
suppose in above objects, if I am going to edit 0th index values,
and I have updated "value": "rest", instead of "value": "test" and
"label": "test" need to keep as it is. So in that case,
it will allow to update the values.
{
"value": "rest",
"label": "test"
},
But if I tried to enter "label": "bb" and "label": "dd",
so it will return false, because these values are already available in above objects.
isLabelExist() {
const formData = this.editStaticParametersForm.value;
const currentIndex: number = this.StaticData.values.indexOf(this.selectedRowValue);
if (formData.label_value && this.StaticData) {
var isPresent = this.StaticData.values.some(function (el) {
return el.label === formData.label_value
});
if (isPresent) {
return false;
}
}
return true;
}
using find (or some) you can check the "index" (add a second argument to the function find), so,
var isPresent = this.StaticData.values.some(function (el,i) {
return el.label === formData.label_value && i!=currentIndex
});
Really in .ts we use arrow flat and use const or let, not var
const isPresent = this.StaticData.values.some((el,i)=> {
return el.label === formData.label_value && i!=currentIndex
});
Or
const isPresent = this.StaticData.values.some(
(el,i)=> el.label === formData.label_value && i!=currentIndex);
I would like to map an array where if one of the values equal to a variable then I change the isChecked key for all objects in this array. for e.g.
input array:
[
[
{
"name": "size",
"value": "XS",
"isChecked": false
},
{
"name": "colors",
"value": "black",
"isChecked": false
}
],
[
{
"name": "size",
"value": "XXXL",
"isChecked": false
},
{
"name": "colors",
"value": "brown",
"isChecked": false
}
],
[
{
"name": "size",
"value": "S",
"isChecked": false
},
{
"name": "colors",
"value": "green",
"isChecked": false
}
]
]
input value: black
output:
[
[
{
"name": "size",
"value": "XS",
"isChecked": true
},
{
"name": "colors",
"value": "black",
"isChecked": true
}
],
[
{
"name": "size",
"value": "XXXL",
"isChecked": false
},
{
"name": "colors",
"value": "brown",
"isChecked": false
}
],
[
{
"name": "size",
"value": "S",
"isChecked": false
},
{
"name": "colors",
"value": "green",
"isChecked": false
}
]
]
maybe should i use some callback,promise? How to map this array? I have to somehow return to the value I missed. In this case, if the value in the array is found then all elements in this array should be marked as isChecked = true.
i've got something like this now:
this.allVariants.map((variant, key) => {
return variant.map((opts, k) => {
if (opts.value == val && !opts.isChecked) {
let mapped = variant.map(op => op.isChecked = true);
} else {
let mapped = variant.map(op => op.isChecked = false);
}
return opts
})
})
You could use map method and inside some to check if element exists in sub-array or not.
const data = [[{"name":"size","value":"XS","isChecked":false},{"name":"colors","value":"black","isChecked":false}],[{"name":"size","value":"XXXL","isChecked":false},{"name":"colors","value":"brown","isChecked":false}],[{"name":"size","value":"S","isChecked":false},{"name":"colors","value":"green","isChecked":false}]]
const res = data.map(arr => {
const check = arr.some(({value}) => value == 'black');
return check ? arr.map(e => ({...e, isChecked: true})) : arr
})
console.log(res)
Perhaps you're looking for something like this? As you can see there's a simple map function which will return an array of the relevant values depending on what was input into the function. It will simply map over the provided arrray and update the relevant objects, provided that the find function doesn't return null.
It achieves this by seeing if the provided value can be found within a nested array via using the found function that I've implemented, provided this returns true, it will then use the mutate function. The idea was that you may want to further change different properties on the given object(s) in future, hence why it has a dedicated function.
My answer is similar to #NenadVracar only I broke it up a little more into multiple functions that consume a single line.
let data = [[{name:"size",value:"XS",isChecked:!1},{name:"colors",value:"black",isChecked:!1}],[{name:"size",value:"XXXL",isChecked:!1},{name:"colors",value:"brown",isChecked:!1}],[{name:"size",value:"S",isChecked:!1},{name:"colors",value:"green",isChecked:!1}]];
// A function that states if relevant object with value exists.
let found = v => a => a.some(({value}) => value == v);
// A function used to return data that has been changed, specifically isChecked = true.
let mutate = a => a.map(i => ({...i, isChecked: true}));
// A function to return the desired array, takes an array and a value.
let map = v => a => a.map(o => found(v)(o) ? mutate(o) : o);
console.log(map('black')(data));
Given that I have a JSON structure like this:
{
"firstData": [{
"secondData": [{
"thirdData": [{
"value": "whatever"
}]
}]
}]
}
And I need to map from thirdData value === "whatever"
So I am doing
const result = firstData.map(first => {
return first.secondData.map(second => {
return second.thirdData.map(third => {
return third.value === 'whatever';
});
});
});
And this works somewhat fine, but the result is a another deeply nested array (like [ [ [ {results..} ] ] ]). I know I can flatten this to a single array by other means, but I feel like I am miss using .map(). How can I modify this result to a single array that contains the values of thirdData where the value is what ever I want?
The desired result for this would be a single array of thirdData objects:
[{ value: 'whatever'}, ... {n}]
You can use Array#reduce for reducing into a single value(in this case single array) and Array#forEach for iterating over the nested array.
const data = {
"firstData": [{
"secondData": [{
"thirdData": [{
"value": "whatever"
}]
}]
}]
}
const result = data.firstData.reduce((arr, first) => {
// iterate over the second level array
first.secondData.forEach(second => {
// iterate over the third level array
second.thirdData.forEach(third => {
// push the value into the result array,
// change here, in case you want the value
//arr.push(third.value === 'whatever');
// in case you need the object then do it like
if(third.value === 'whatever') arr.push(third);
});
});
// return the array reference for the next iteration
return arr;
// set the initial value as an array for the result
}, []);
console.log(result);
If you want a flat result, this isn't a use case for map. The simple solution is just to use an array you close over and push to:
const result = [];
firstData.forEach(first => {
return first.secondData.forEach(second => {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
});
});
Live Example with a slight extension to your minimal provided data:
const data = {
"firstData": [{
"secondData": [{
"thirdData": [{
"value": "whatever",
"label": "third #1.1"
},
{
"value": "whatever",
"label": "third #1.2"
},
{
"value": "unrelated",
"label": "unrelated"
}
]
}]
},
{
"secondData": [{
"thirdData": [{
"value": "another unrelated"
},
{
"value": "whatever",
"label": "third #2"
}
]
}]
}
]
};
const result = [];
data.firstData.forEach(first => {
return first.secondData.forEach(second => {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
});
});
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Note the filter on the thirdData and using spread notation to push that data into result.
That assumes you want the entry from thirdData that has .value === 'whatever' rather than a true/false. If you want the true/false instead, change that filter to map.
Or the for-of equivalent:
const result = [];
for (const first of firstData) {
for (const second of first.secondData) {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
}
}
Live Example with a slight extension to your minimal provided data:
const data = {
"firstData": [{
"secondData": [{
"thirdData": [{
"value": "whatever",
"label": "third #1.1"
},
{
"value": "whatever",
"label": "third #1.2"
},
{
"value": "unrelated",
"label": "unrelated"
}
]
}]
},
{
"secondData": [{
"thirdData": [{
"value": "another unrelated"
},
{
"value": "whatever",
"label": "third #2"
}
]
}]
}
]
};
const result = [];
for (const first of data.firstData) {
for (const second of first.secondData) {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
}
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
(Same note about filter/map.)
As with all array operations, you can shoehorn this into reduce, and I guarantee you you'll get answers primarily using reduce, but there's no good reason to use reduce here.
const result = firstData.reduce((result, first) => {
return first.secondData.reduce((result, second) => {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
return result;
}, result);
}, []);
Again, though, there's no good reason for that. It's just more complicated.
Live Example with a slight extension to your minimal provided data:
const data = {
"firstData": [{
"secondData": [{
"thirdData": [{
"value": "whatever",
"label": "third #1.1"
},
{
"value": "whatever",
"label": "third #1.2"
},
{
"value": "unrelated",
"label": "unrelated"
}
]
}]
},
{
"secondData": [{
"thirdData": [{
"value": "another unrelated"
},
{
"value": "whatever",
"label": "third #2"
}
]
}]
}
]
};
const result = data.firstData.reduce((result, first) => {
return first.secondData.reduce((result, second) => {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
return result;
}, result);
}, []);
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
(Same note about filter/map.)
I am working on a D3.JS chart using an array named "dataset" where each entry is an object with a key and value attributes, such as the following:
dataset=
[
{"key":"alpha", "value": [ {}, { } ...]},
{"key":"beta", "value": [ { }, { } ...]},
{"key":"gamma", "value": [ {}, { } ...]},
{"key":"delta", "value": [ { }, { } ...]}
];
I need to extract one of those objects to create a new array. I have tried the following:
filteredDataset = dataset.filter(function(d){ console.log("d",d); if(d.key === "gamma") return d});
I can see in the console that I am accessing each object in the dataset, but the resulting filteredDataset comes out empty. What am I doing wrong?
For clarity filter should be used by returning a boolean:
Like:
filteredDataset = dataset.filter(function(d){ return d.key === "gamma"})
And on my end the code
var dataset = [
{"key":"alpha", "value": [ {}, { }]},
{"key":"beta", "value": [ { }, { }]},
{"key":"gamma", "value": [ {}, { }]},
{"key":"delta", "value": [ { }, { }]}
];
filteredDataset = dataset.filter(function(d){ return d.key === "gamma"})
Outputs:
[ { key: 'gamma', value: [ {}, {} ] } ]
So please double check your code
dataset.filter(function(d){return d.key === 'gamma';});
This returns the data where key === gamma.
https://github.com/mbostock/d3/wiki/Selections#filter