Calculate values returned from loop - javascript

I created method what needs to return proper length of items:
#Input() items: any[];
calculateCount(type?: string | string[]): number {
if (typeof type === 'object') {
for (let value of type) {
this.items && this.items.filter((item) => item.type === value).length;
}
//TODO: return sum of values from loop;
}
if (typeof type === 'string') {
return this.items && this.items.filter((item) => item.type === value).length;
}
return this.items && this.items.length;
}
But I need suggestions how to return sum of values from loop. Thanks

let total = loopitems.reduce((acc, val) => acc += val.itemToSumUp, 0);
loopitems being all the items needed to be counted.
itemToSumUp is the property wich you need to sum (don't use .xxx if you need the entire object.)
0 = start count from zero.

I was looking for the solution and found one by using .some() method instead of for loop calculation.
Here what I've done:
calculateCount(type?: string | string[]): number {
if (Array.isArray(type)) {
return this.items && this.items.filter((item) => type.some((someType) => someType === item.type)).length;
}
if (typeof type === 'string') {
return this.items && this.items.filter((item) => item.type === value).length;
}
return this.items && this.items.length;
}
I hope this should be helpful.

Related

Javascript : filter array of object remove all objects

I got a simple question, been hours on it and can't figuring out the solution. I got an array of object. I want to remove the object that has same values that a variable I pass.
My problem is that it removes all the objects, even those that are not similar to my variable.
Here is my code
function appSelect(variable) {
//we check if the object already exists in my array {id:x, value:y}
const found = myArray.find(obj => {
return (obj.id === variable.id && obj.value === variable.value);
});
if (found) {
//If find it, I want to remove it from my array
const filtered = myArray.filter(obj => {
return (obj.id !== variable.id && obj.value !== variable.value);
})
//Return empty array
}
I receive the value from a select form. For exemple I got myArray = [{id: 1, value: 12},{id: 2, value: 12},{id: 5, value: 12}] and variable = {id: 2, value: 12}
What I did wrong?
The reason is the code below:
return (obj.id !== variable.id && obj.value !== variable.value)
Which means if id or value is the same,then it will be filtered.
You can change it to
return !(obj.id === variable.id && obj.value === variable.value)
Full code:
function appSelect(variable) {
//we check if the object already exists in my array {id:x, value:y}
const found = myArray.find(obj => {
return (obj.id === variable.id && obj.value === variable.value);
});
if (found) {
//If find it, I want to remove it from my array
const filtered = myArray.filter(obj => {
return !(obj.id === variable.id && obj.value === variable.value);
})
//Return empty array
}
This is a failed DeMorgan's Law. You want the opposite of obj.id === variable.id && obj.value === variable.value, which is !(obj.id === variable.id && obj.value === variable.value) or obj.id !== variable.id || obj.value !== variable.value when DeMorgan's Law is applied.
const filtered = myArray.filter((obj) => {
return obj.id !== variable.id || obj.value !== variable.value;
});
if one of the value is different then it's not the same objet, note that the first found check is unnecessary
function appSelect(variable, arr) {
return arr.filter(obj => (obj.id !== variable.id || obj.value !== variable.value))
}
You can try this code:
const myArray = [
{ id: 1, value: 12 },
{ id: 2, value: 12 },
{ id: 5, value: 12 },
];
const variable = { id: 2, value: 12 };
function appSelect(variable) {
//we check if the object already exists in my array {id:x, value:y}
const found = myArray.find((obj) => {
return obj.id === variable.id && obj.value === variable.value;
});
if (found) {
//If find it, I want to remove it from my array
const filtered = myArray.filter((obj) => {
// if you found the object variable in your array then you return nothing
if (obj.id === variable.id && obj.value === variable.value) {
return;
}
// if the current object is not object variable then return it
return obj;
});
return filtered;
}
//Return empty array
return myArray;
}
console.log(appSelect(variable));

Finding conditional index of an item in a list of objects

I need to find index of an item from a list of objects.
First I have to check if that item exist with status of WAITING.
If no item with that status exist, then find something else with any other status.
Is there any better solution for this?
x in this code coming from a map
MainArray.map((x) => {
let itemIndex = orders?.findIndex(item => item.status === 'WAITING' && item.slot=== (x));
if (itemIndex === -1) {
itemIndex = orders && orders.findIndex(item => item.slot === (x));
}
return itemIndex;
}
There won't be a reasonble "single line solution" (those are over-rated in any case; hard to read, hard to debug); but you can avoid searching through the array twice by using a for loop:
const indexes = MainArray.map((x) => {
let bySlotIndex;
for (let index = 0, length = orders?.length; orders && index < length; ++index) {
const order = orders[index];
if (item.slot === x) {
bySlotIndex = bySlotIndex ?? index;
if (item.status === "WAITING") {
return index; // Found a waiting one, we're done
}
}
}
return bySlotIndex ?? -1;
});
Or if you really want to use findIndex, you can avoid some searching by finding the first one with a matching slot first:
const indexes = MainArray.map((x) => {
const bySlotIndex = orders?.findIndex(order => order.slot === x) ?? -1;
if (bySlotIndex === -1) {
return -1;
}
const waitingIndex = orders.findIndex(
order => order.status === 'WAITING' && order.slot === x,
bySlotIndex // Start at the first one with a matching slot
);
return waitingIndex === -1 ? bySlotIndex : waitingIndex;
});
Note that both of the above return -1 if orders is falsy, rather than undefined. Tweak if you really wanted undefined.
You can use findIndex to look for an item with status equal to 'WAITING'. in case, no item exists, use findIndex to return the first item with a status.
const arr = [{status: "WAITING", slot : 1}, {status: "NOTWAITING", slot: 2}];
const getIndex = (arr) => {
const idx = arr.findIndex(x => x.status === 'WAITING');
return idx !== -1 ? idx : arr.findIndex(x => x.status);
}
console.log(getIndex(arr));

how to check if object values are empty?

I have a problem with this structure:
const ob = {
name: ''
ob: {}
arr: []
}
I want to check if all values, are empty.
If I have only strings and arrays, the problem is trivial, but with an object my best solution is something like that,
const test = Object.values(ob).reduce((acc, curr) => {
const isPlainObject = typeof curr === 'object' && !Array.isArray(curr);
if (isPlainObject) !Object.values(curr).length ? (acc = false) : null;
else !curr.length ? (acc = false) : null;
return acc;
}, true);
I'm not satisfied with this, did anybody face similar problem and can help me with that?
You could check the various types and then either the length or the count of (own enumerable) keys or the value.
const
isEmpty = object => Object.values(object).every(v => {
if (Array.isArray(v)) return v.length === 0;
if (v && typeof v === 'object') return Object.keys(v).length === 0;
return v === '';
}),
ob = { name: '', ob: {}, arr: [] };
console.log(isEmpty(ob));
Maybe not so much better than your solution, C233. But I'll give it a shot ;)
const isEmpty = (val) => {
if(!val) {
return true;
}
if (typeof val === 'object') {
return Object.values(val).length === 0;
}
if (typeof val === 'string') {
return val.length === 0;
}
return false;
}
const hasEmptyProps = (obj) => Object.values.map(isEmpty).reduce((result, curr) => result && curr, true);

How to check if object is empty in javascript for all levels in object

I wanted to find out if my object is empty or not for all its nested objects and key-value pairs.
for e.g.,
const x = {
a:"",
b:[],
c:{
x:[]
},
d:{
x:{
y:{
z:""
}
}
}
};
this should be an empty object and if any of this contains single value then it should be non empty.
Here is the way to do what using recursion
const x = {
a:"",
b:[],
c:{
x:[]
},
d:{
x:{
y:{
z:''
}
}
}
};
function checkEmpty(obj){
for(let key in obj){
//if the value is 'object'
if(obj[key] instanceof Object === true){
if(checkEmpty(obj[key]) === false) return false;
}
//if value is string/number
else{
//if array or string have length is not 0.
if(obj[key].length !== 0) return false;
}
}
return true;
}
console.log(checkEmpty(x))
x.d.x.y.z = 0;
console.log(checkEmpty(x));
You can write a recursive function like following. Function creates a set with 2 possible values true and false. If the size of set is 1 and the value being false, which mean that the object is empty.
const x = {a:"",b:[],c:{x:[]},d:{x:{y:{z:""}}}};
function isEmpty(o, r = new Set()) {
for (let k in o) {
if(typeof o[k] === "object") {
if(Array.isArray(o[k])) r.add(!!o[k].length);
else isEmpty(o[k],r);
} else r.add(!(o[k] === "" || o[k] === undefined || o[k] === null));
}
return r;
}
let result = isEmpty(x);
console.log(result.has(false) && result.size == 1);
I will use a recursive approach for this one, we iterate over the object.keys() and check is every value related to the key is empty, in the case the value is an object, we go one level deeper to check it.
const x = {
a:"",
b:[],
c:{x:[]},
d:{x:{y:{z:""}}}
};
const x1 = [0,0,0];
const x2 = {0:0,1:0,2:0};
const isEmpty = (obj, empty=true) =>
{
Object.keys(obj).forEach((key) =>
{
if (typeof obj[key] === "object")
empty = isEmpty(obj[key], empty);
else
empty = empty && (obj[key].length === 0);
// Return early if we detect empty here.
if (!empty) return empty;
});
return empty;
}
console.log("original x: ", isEmpty(x));
x.a = "I'm not empty";
console.log("x after edit: ", isEmpty(x));
console.log("x1: ", isEmpty(x1));
console.log("x2: ", isEmpty(x2));
try (we use here recursion, fat arrow, obj. keys, reduce, ternary operator and object checking)
let isEmpty = o => o.constructor.name === "Object" ?
Object.keys(o).reduce((y,z)=> y&&isEmpty(o[z]) ,true) : o.length == 0;
const x = {
a:"",
b:[],
c:{
x:[]
},
d:{
x:{
y:{
z:""
}
}
}
};
let isEmpty = o => o.constructor.name === "Object" ?
Object.keys(o).reduce((y,z)=> y&&isEmpty(o[z]) ,true) : o.length == 0;
// Test
console.log(isEmpty(x));
x.d.x.y.z="Smile to life and life will smile to you";
console.log(isEmpty(x));

Converting lodash's `_.pull` to vanilla JS? [duplicate]

This question already has answers here:
Remove empty elements from an array in Javascript
(49 answers)
Closed 5 years ago.
I'm having an issue with this function that recursively removes empty values from an object:
const _ = require('lodash')
function sanitize(object) {
Object.entries(object).forEach(([key, val]) => {
if (
val == null ||
Number.isNaN(val) ||
(typeof val === 'string' && isOnlyWhitespace(val)) ||
(typeof val === 'object' && Object.keys(sanitize(val)).length === 0)
) {
delete object[key]
}
});
// Remove `undefined` values leftover from using `delete` on an array.
if (Array.isArray(object)) {
_.pull(object, undefined); // THIS IS THE LINE IM TRYING TO CHANGE
}
return object;
}
function isOnlyWhitespace(str) {
return !(/\S/).test(str.trim());
}
I'm trying to replace _.pull(object, undefined) with vanilla JS, but nothing seems to give the right output (I've tried using stuff like filter.)
Here is a snippet you can run to see both outputs:
// LODASH VERSION
function lodashSanitize(object) {
Object.entries(object).forEach(([key, val]) => {
if (
val == null ||
Number.isNaN(val) ||
(typeof val === 'string' && isOnlyWhitespace(val)) ||
(typeof val === 'object' && Object.keys(lodashSanitize(val)).length === 0)
) {
delete object[key]
}
});
// Remove `undefined` values leftover from using `delete` on an array.
if (Array.isArray(object)) {
_.pull(object, undefined); // THIS IS THE LINE IM TRYING TO CHANGE
}
return object;
}
// MY VERSION
function mySanitize(object) {
Object.entries(object).forEach(([key, val]) => {
if (
val == null ||
Number.isNaN(val) ||
(typeof val === 'string' && isOnlyWhitespace(val)) ||
(typeof val === 'object' && Object.keys(mySanitize(val)).length === 0)
) {
delete object[key]
}
});
// Remove `undefined` values leftover from using `delete` on an array.
if (Array.isArray(object)) {
object = object.filter(val => val != null) // THIS IS MY ATTEMPT
}
return object;
}
function isOnlyWhitespace(str) {
return !(/\S/).test(str.trim());
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<button id="lodash">Show lodash output</button>
<button id="me">Show my output</button>
<p id="output" />
<script>
/**
* Fiddle-related code, you can ignore this
*/
const lodashBtn = document.querySelector('#lodash')
const meBtn = document.querySelector('#me')
const output = document.querySelector('#output')
function createExampleInput() {
const input = {
name: 'John',
grades: [
90,
undefined,
50,
null
]
};
return input;
}
lodashBtn.addEventListener('click', () => {
output.textContent = JSON.stringify(lodashSanitize(createExampleInput()), null, 4)
});
meBtn.addEventListener('click', () => {
output.textContent = JSON.stringify(mySanitize(createExampleInput()), null, 4)
});
</script>
The problem is that filter returns a new array. Why not just use a for loop and splice:
if (Array.isArray(object)) {
for (var i = object.length - 1; i >= 0; i--) {
if (object[i] === undefined) {
object.splice(i, 1);
}
}
}

Categories