I have 2 Objects in an array with 2 scenarios:
If test_status_id is accepted for all objects in array, then case_status_id should be completed, otherwise case_status_id should be pending. How do I go about doing that?
const result = [{
id:1,
case_status_id : 1(pending),
case_test_map : [{
id:1,
test_status_id: 1(accepted)
},
{
id:2,
test_status_id: 2(rejected)
}]
},
{
id:2,
case_status_id : 2(completed),
case_test_map : [{
id:1,
test_status_id: 1(accepted)
},
{
id:2,
test_status_id: 1(accepted)
}]
}]
Try this
result.forEach(res => {
const resultStatuses = res.case_test_map.map(test => test.test_status_id);
if(resultStatuses.every( (val, i, arr) => val === arr[0] ) ) {
if(resultStatuses[0] === 'accepted') {
res.case_status_id = 'accepted'
}
}
else {
res.case_status_id = 'pending'
}
})
sources:
Check if all values of array are equal
Try the following function, it does what you need:
function calculateCaseStatus(result) {
// at first, iterate over each element of result array
for(let res of result) {
// assume, 'case_status_id' would be set to 2 by default(i.e. 'completed')
let flag = true;
// now, check if any 'test_status_id' is set to 2(i.e. rejected)
// for that, first iterate over each element of 'case_test_map' array
for(let cmp of res.case_test_map) {
if(cmp.test_status_id !== 1) {
// if any test_status_id is not completed, then
// case_status_id can't be 2(i.e. completed)
// so, make the flag false
flag = false;
break;
}
}
// if flag is true, set case_status_id to 2 (i.e. completed)
if(flag) {
res.case_status_id = 2;
} else {
// else set case_status_id to 1 i.e.(pending)
res.case_status_id = 1;
}
}
}
You've to call it like:
calculateCaseStatus(result);
// and to check the result
console.log(result);
Related
This question already has answers here:
Return matching objects from array of objects
(4 answers)
Closed 3 years ago.
Create a function that takes an array of people objects and returns the first found astronaut object from the array.
This is the code that I have created;
function findFirstAstronaut(people) {
for (let i = 0; i < people.length; i++) {
if (people.astronaut[i] === false) {
return null
}
else if (people.astronaut[i]) {
return people[i]
}
}
My code is run against this test;
describe("findFirstAstronaut", () => {
it("returns null if no Astronaut is in the array", () => {
expect(findFirstAstronaut([])).to.be.null;
});
it("returns a person object who is an astronaut", () => {
const astronaut = { name: "Tim Peake", isAstronaut: true };
expect(findFirstAstronaut([astronaut])).to.have.keys([
"name",
"isAstronaut"
]);
expect(findFirstAstronaut([astronaut]).isAstronaut).to.be.true;
});
it("returns the first astronaut from the array", () => {
const astronauts = [
{ name: "Johnny Karate", isAstronaut: false },
{ name: "Neil Armstrong", isAstronaut: true },
{ name: "Valentina Tereshkova", isAstronaut: true },
{ name: "Bert Macklin", isAstronaut: false },
{ name: "Eileen Collins", isAstronaut: true },
{ name: "Kip Hackman", isAstronaut: false }
];
expect(findFirstAstronaut(astronauts)).to.eql({
name: "Neil Armstrong",
isAstronaut: true
});
});
});
How do I fix my code?
ES6 introduces a new way to achieve this, if ES6 is an option for you:
myArray.find(item => {
return item.isAstronaut
})
Or even more abbreviated:
myArray.find(item => item.isAstronaut)
find() is a one of the new iterators, along with filter() and map() and others for more easily working with arrays. find() will return the first item in your array that matches the condition. The => or "arrow function" means that you do not need to explicitly include the return statement.
Read more about ES6 iterators.
You need to use the index for the array.
people[i] // for the object
people[i].isAstronaut // for a property of the object
Then you need only a check if isAstronaut is true and return with the item.
At the end outside of the for loop, return null, for a not found astronaut.
If you check inside the loop, you will return too early with the wrong result.
function findFirstAstronaut(people) {
for (let i = 0; i < people.length; i++) {
if (people[i].isAstronaut) {
return people[i];
}
}
return null;
}
One liner
arr.filter(item => item.isAstronaut)[0]
You could simply filter out array elements that have an isAstronaut property equal to false using Array.prototype.filter. I prefer filter to Array.prototype.find since ES6 isn't supported in every browser.
Once you have the filtered array simply take the element in the 0 index position. Something like below:
const astronauts = [{
name: "Johnny Karate",
isAstronaut: false
},
{
name: "Neil Armstrong",
isAstronaut: true
},
{
name: "Valentina Tereshkova",
isAstronaut: true
},
{
name: "Bert Macklin",
isAstronaut: false
},
{
name: "Eileen Collins",
isAstronaut: true
},
{
name: "Kip Hackman",
isAstronaut: false
}
];
//Array destructuring to get the first astronaut:
var [firstAstronautFound] = astronauts.filter(el => el.isAstronaut);
//Line above is same as doing this:
//var firstAstronautFound = astronauts.filter(el => el.isAstronaut)[0];
console.log(firstAstronautFound.name);
First, you may need to check whether there is any item in array or else return null.
Second, you have to check for the property
Third, you have to check for the value of the property isAstronaut
function findFirstAstronaut(people) {
if (people.length > 0)
{
for (let i = 0; i < people.length; i++) {
if (("name" in people[i]) && ("isAstronaut" in people[i])) {
if (people[i].isAstronaut)
return people[i];
else
return true;
}
}
}
else
return null;
}
Below is running code snippet for the javascript object and array.
I have one jsonObj and here the ResultElementLevel could be the array or
object.
According to I just put if else condition and compare if Array and 'object'.
My question is,How would it be possible without if else condition?
can we write one function which compare object and Array inside single if.
The jsonObj is populating dynamically.
Here it would be possible CHECK object is also come into the Array or Object.
var jsonObj = {
"Response": {
"Errors": {
"Check": {
"_attributes": {
"id": "51416",
"name": "lucyocftest090601"
},
"CheckLevel": {
},
"ResultElementLevel": {
"_text": "Line No (2) [Missing Reporting Category] "
}
}
},
"Success": {
}
}
}
iterateObjorArr(jsonObj);
function iterateObjorArr(jsonObj){
let checkArr = jsonObj.Response.Errors.Check;
let checkID = checkArr._attributes.id;
let checkName = checkArr._attributes.name;
let status = 'failed';
let resultElementLevel = checkArr.ResultElementLevel;
let errorUploadArr = [];
let errorUploadObj;
if (Array.isArray(resultElementLevel)) {
resultElementLevel.map(function (data, index) {
errorUploadObj = {
'id': checkID,
'checkName': checkName,
'status': status,
'errors/warnings': data._text
};
errorUploadArr.push(errorUploadObj);
});
} else {
if (typeof (resultElementLevel) === 'object') {
errorUploadObj = {
'id': checkID,
'checkName': checkName,
'status': status,
'errors/warnings': resultElementLevel._text
};
errorUploadArr.push(errorUploadObj);
}
}
console.log("errorUploadArr", errorUploadArr);
}
You can test to see if resultElementLevel has the length property or not using hasOwnProperty(). Arrays have a length while objects do not (generally):
if (resultElementLevel.hasOwnProperty('length')) {
// Handle it as an array
} else {
// Handle as an object
}
This will, however, only work if the object assigned to resultElementLevel is guaranteed to not have a length property.
My question is,How would it be possible without if else condition? can we write one function which compare object and Array inside single if.
I don't think you'd want to get rid of the condition, but being able to deal with the passed data the same way, wether it's an array, a single item, or null/undefined
You could normalize the data first
function toArray(value){
return value == null? []:
Array.isArray(value)? value:
//isArrayLike(value)? Array.from(value):
[value];
}
//Objects that look like Arrays
function isArrayLike(value){
return value !== null && typeof value === "object" && value.length === (value.length >>> 0);
}
so that from here on, you always deal with an Array:
let errorUploadArr = toArray(checkArr.ResultElementLevel)
.map(function(item){
return {
id: checkID,
checkName: checkName,
status: status,
"errors/warnings": item._text
};
});
var jsonObj = {
Response: {
Errors: {
Check: {
_attributes: {
id: "51416",
name: "lucyocftest090601"
},
CheckLevel: {},
ResultElementLevel: {
_text: "Line No (2) [Missing Reporting Category] "
}
}
},
Success: {}
}
};
iterateObjorArr(jsonObj);
function toArray(value) {
return value == null ? [] :
Array.isArray(value) ? value :
//isArrayLike(value)? Array.from(value):
[value];
}
//Objects that look like Arrays
function isArrayLike(value) {
return value !== null && typeof value === "object" && value.length === (value.length >>> 0);
}
function iterateObjorArr(jsonObj) {
let checkArr = jsonObj.Response.Errors.Check;
let checkID = checkArr._attributes.id;
let checkName = checkArr._attributes.name;
let status = "failed";
let errorUploadArr = toArray(checkArr.ResultElementLevel)
.map(function(data) {
return {
id: checkID,
checkName: checkName,
status: status,
"errors/warnings": data._text
}
});
console.log("errorUploadArr", errorUploadArr);
}
.as-console-wrapper{top:0;max-height:100%!important}
I have an array arr=[{key: 'first'},{key: 'second'} ...], I want to go through that array and check if an element with a specific key exist and do something.
arr.forEach(element => {
if(element.key === 'first') {
// do something
} else {
// do something else
}
if(element.key === 'second') {
// do something
} else {
// do something else
}
});
The thing is that when it goes through array, it first sees 'first' and it goes through if() statement, but it also goes through else() statement of 'second' item because it did't find it, and so it does when foreach goes through other items in array. I don't know how to make it to go through array one time and set if() else() appropriately. So when it finds 'first' I want it just to do if() of that item and not else() of others. I hope you understand. Thanks in advance!
Edit: My logic behind this code is that when I call database and find that array if there is no 'firstExercise' in that array, then it should add it to that db (I am using firebase so in else() I am calling db to create that exercise), and if there is'firstExercise' in array do nothing. Sorry for not clarifying that.
Edit2: Here is my original code:
res.forEach(element => {
if (this.numbOfFinished === 1) {
if (element.key === 'firstExercise') {
console.log('has')
} else {
awardName = 'firstExercise'
this.homeService.addAward(this.userId, awardName).then(() => {
this.awardName = 'firstExercise';
this.awarded = true;
});
}
}
});
if (this.numbOfFinished === 5) {
if (element.key === 'fifthExercise') {
console.log('has')
} else {
awardName = 'fifthExercise'
this.homeService.addAward(this.userId, awardName).then(() => {
this.awardName = 'fifthExercise';
this.awarded = true;
});
}
}
});
I personally like to create arrays which makes the relation between a key and functions. So I can iterate and call the proper one.
What I like in this solution instead of using a switch/case or if/else forest is that you can apply automatic treatments and that you can easily make it to evolve.
const mapKeyFunc = [{
key: 'first',
func: async(x) => {
console.log('Do something for key first');
// here you can perform an async request and modify `this`
},
}, {
key: 'second',
func: async(x) => {
console.log('Do something for key second');
// here you can perform an async request and modify `this`
},
}];
const doStuff = async(arr) => {
for (let i = 0; i < arr.length; i += 1) {
const mapElement = mapKeyFunc.find(x => x.key === arr[i].key);
await mapElement.func.call(this, arr[i]);
}
};
const arr = [{
key: 'first',
otherStuff: 0,
}, {
key: 'second',
otherStuff: 42,
}];
doStuff(arr).then(() => {}).catch(e => console.log(e));
If you don't need the treatment to be synchronous, here we have an asynchronous method
const mapKeyFunc = [{
key: 'first',
func: async(x) => {
console.log('Do something for key first');
// here you can perform an async request and modify `this`
},
}, {
key: 'second',
func: async(x) => {
console.log('Do something for key second');
// here you can perform an async request and modify `this`
},
}];
const doStuff = async(arr) => {
await Promise.all(arr.map(x => mapKeyFunc.find(y => y.key === x.key).func.call(this, x)));
};
const arr = [{
key: 'first',
otherStuff: 0,
}, {
key: 'second',
otherStuff: 42,
}];
doStuff(arr).then(() => {}).catch(e => console.log(e));
If you only want one option out of them to be executed (and then exiting out of the function), you could use else if statements like so:
arr.forEach(element => {
if(element.key === 'first') {
// do something
} else if(element.key === 'second') {
// do something
} else {
// do something else
}
});
This will do pretty much exactly what you expect. If element.key == 'first', it'll do block one. Else, if element.key == 'second', it'll do block two. Else, it'll do block three.
You need to merge the if statements like this:
arr.forEach(element => {
if(element.key === 'first') {
// do something
} else if(element.key === 'second') {
// do something else
}
});
element.key has a single value in each iteration and you therefore need a single level of conditioning.
i have one object and its having service array i checked if any service id and offer id match with object its decrease count value and once count reach zero need to remove that object.please check my try in fiddle. i can able to reduce but while reaching zero not able to remove
const obj = {
name:'saloon',
services:[
{
sid:1,
offid:20,
count:2
},
{
sid:2,
offid:18,
count:1
},
{
sid:3,
offid:15,
count:3
}
]
}
given values : based on this service and offer id count should decrease once count reach zero need to remove that object
const servid = 2
const offid = 18
mycode
obj.services = obj.services.map(data => {
if(data.sid == servid && data.offid == offid ){
return data.count > 1 && {
sid:data.sid,
offide:data.offid,
count:data.count -1
}
}else{
return data
}
})
console.log(obj);
expected result :
const result = {
name:'saloon',
services:[
{
sid:1,
offid:20,
count:2
},
{
sid:3,
offid:15,
count:3
}
]
}
Use array#forEach to iterate through your array and check each sid and offid inside service, in case of match update the count value after that check if count value is less than or equal to zero, if it is, then using push its index into indexes array. After that, you can iterate through indexes array and delete those values in services array using array#splice.
const obj = { name:'saloon', services:[ { sid:1, offid:20, count:2 }, { sid:2, offid:18, count:1 }, { sid:3, offid:15, count:3 } ] };
const servid = 2;
const offid = 18;
var indexes = [];
obj.services.forEach(function(service, index) {
if(service.sid === servid && service.offid === offid){
--service.count;
}
if(service.count <= 0)
indexes.push(index);
});
indexes.reverse().forEach(function(index){
obj.services.splice(index, 1);
});
console.log(obj);
Use .forEach() to decrease the count, then .filter() to remove elements with count == 0:
const obj = {
name: 'saloon',
services: [{
sid: 1,
offid: 20,
count: 2
}, {
sid: 2,
offid: 18,
count: 1
}, {
sid: 3,
offid: 15,
count: 3
}]
}
const servid = 2
const offid = 18
obj.services.forEach((data, i) => {
if (data.sid == servid && data.offid == offid) {
data.count--;
}
})
obj.services = obj.services.filter(data => data.count > 0);
console.log(obj);
I have this json object returned from an API that has a few quirks, and I'd like to normalize it so I can process the input the same for every response. These means getting rid of superfluous keys:
Response:
{
_links: {...},
_embedded: {
foo: [
{
id: 2,
_embedded: {
bar: []
}
}
]
}
}
So I'd like to remove all the _embedded keys and flatten it, like so:
{
_links: {...},
foo: [
{
id: 2,
bar: []
}
]
}
This is what I have at the moment, but it only works for the top level and I don't think it'll play well with arrays.
_.reduce(temp1, function(accumulator, value, key) {
if (key === '_embedded') {
return _.merge(accumulator, value);
}
return accumulator[key] = value;
}, {})
Loop in recursion on all of your keys, once you see a key which start with _
simply remove it.
Code:
var
// The keys we want to remove from the Object
KEYS_TO_REMOVE = ['_embedded'],
// The data which we will use
data = {
_links: {'a': 1},
_embedded: {
foo: [
{
id: 2,
_embedded: {
bar: []
}
},
{
id: 3,
_embedded: {
bar: [
{
id: 4,
_embedded: {
bar: []
}
}
]
}
}
]
}
};
/**
* Flatten the given object and remove the desired keys if needed
* #param obj
*/
function flattenObject(obj, flattenObj) {
var key;
// Check to see if we have flatten obj or not
flattenObj = flattenObj || {};
// Loop over all the object keys and process them
for (key in obj) {
// Check that we are running on the object key
if (obj.hasOwnProperty(key)) {
// Check to see if the current key is in the "black" list or not
if (KEYS_TO_REMOVE.indexOf(key) === -1) {
// Process the inner object without this key
flattenObj[key] = flattenObject(obj[key], flattenObj[key]);
} else {
flattenObject(obj[key], flattenObj);
}
}
}
return flattenObj;
}
console.log(flattenObject(data));
So, basically you already have almost all of the code you need. All we have to do is wrap it in a function so we can use recursion. You'll see we only add a check to see if it is an object, if it is, we already have a function that knows how to flatten that object, so we'll just call it again with the key that we need to flatten.
function flatten(temp1) { // Wrap in a function so we can use recursion
return _.reduce(temp1, function(accumulator, value, key) {
if (key === '_embedded') {
return _.merge(accumulator, value);
} else if (value !== null && typeof value === 'object') // Check if it's another object
return _.merge(accumulator, flatten(value)) // Call our function again
return accumulator[key] = value;
}, {})
}
I'll be able to test it in a bit, but this should be what you need.
Got it!
function unEmbed(data) {
return _.reduce(data, function(accumulator, value, key) {
const returnableValue = _.isObject(value) ? unEmbed(value) : value;
if (key === 'embedded') {
return _.merge(accumulator, returnableValue);
}
accumulator[key] = returnableValue;
return accumulator;
}, {});
}
Problem before I was returning return accumulator[key] = returnableValue, which worked out to be return returnableValue.