I am trying to find the first processed === true and return the value.
My works seems to work but if there are no processed the code turns undefined instead of <empty string>
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
const myValue = values.reduce((acc, curr) => {
if (curr.primary) {
return curr.value.toLowerCase();
}
}, '');
console.log("My Value: " + myValue);
What am I missing here?
reduce calls the callback function once for each item in the loop.
curr is the current value. acc is the return value from the previous function (or the second argument ('') the first time going around the loop.
Your code completely ignores acc so the value returned by reduce depends entirely on the last value in the array.
Your function tests that value with curr.primary. If that is a true value it return curr.value.toLowerCase(). If it isn't a true value, then it gets to the end of the function without hitting a return statement. Any function that doesn't return will return undefined.
To find the first value that matches a condition, use find not reduce.
Then do a test to use an empty string if you didn't find anything.
const match = values.find(value => value.primary === true);
const myValue = match?.value.toLowerCase() ?? "";
I am trying to find the first processed === true and return the value [else an empty string ""].
You can use Array.prototype.find() with the optional chaining operator (?.) along with the nullish coalescing operator (??) in the case that no value is found:
const array1 = [
{ value: 'bar', processed: false },
{ value: 'foo', processed: false },
];
const myValue1 = array1.find(o => o.processed)?.value.toLowerCase() ?? '';
console.log('myValue1:', myValue1); // "myValue1:" ""
console.log('type:', typeof myValue1); // "type:" "string"
const array2 = [
{ value: 'BAR', processed: false },
{ value: 'FOO', processed: true },
];
const myValue2 = array2.find(o => o.processed)?.value.toLowerCase() ?? '';
console.log('myValue2:', myValue2); // "myValue2:" "foo"
console.log('type:', typeof myValue2); // "type:" "string"
Here's a breakdown of the syntax evaluation for the first value:
const myValue1 = array1.find(o => o.processed)?.value.toLowerCase() ?? '';
// 11111111111111111111111111111 22222222222222222222 44 55
// 33333333333333333333333333333333333333333333333333
// 1. This evaluates to undefined
// 2. So this part is not evaluated, and...
// 3. the entire left side evaluates to undefined
// 4. Because 3 is nullable (null or undefined), when the ?? operator executes...
// 5. the left side (3) is ignored, and the right side (5) becomes the value
In contrast with the value computed from the second array:
const myValue2 = array2.find(o => o.processed)?.value.toLowerCase() ?? '';
// 11111111111111111111111111111 22222233333333333333 55 66
// 44444444444444444444444444444444444444444444444444
// 1. This evaluates to { value: 'FOO', processed: true }
// 2. So this part is evaluated to "FOO"
// 3. which becomes "foo", and...
// 4. the entire left side evaluates to "foo"
// 5. Because 4 is NOT nullable (null or undefined), when the ?? operator executes...
// 6. the left side (4) becomes the final value, and the right side (6) is ignored
To find the first element that meets a condition you should use find method.
Reduce will run on the entire array even after that condition is met since it's purpose is to reduce an entire array into a different data structure (i.e string/object). Find method will exit as soon as an item that meets the condition is found (or after checking the entire array if non of the items does)
As to replacing undefined with an empty string, in the attached snippet I used a or condition (although some would prefer conditional operator), since undefined is falsey, it will insert the empty string.
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
const myValue = values.find(curr => curr.process);
console.log("My Value: " + (myValue?.value?.toLowerCase() || ''));
Best of luck with your project:)
This should be all:
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
const myValue = values.reduce((acc, curr) => curr.process ? curr.value.toLowerCase() : '', '');
console.log("My Value: " + myValue);
you might be better off using a foreach loop to accomplish what you are trying to do:
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
var processedValue = '';
values.forEach(element => {
if(element.process && !processedValue)
processedValue = element.value;
});
console.log(processedValue);
Related
I want to check if an object has a value besides pageSize & pageStart & page , these values arent always all there for example sometimes pagestart will be missing if it equals 0. So checking the length of the object isnt reliable.
let object = {
pageStart: 50,
page: 2
userName: "Bobby"
}
I want to check if the object contains anything besides these values and return a true/false.
One concise option would be to destructure those properties out, use rest syntax to put the rest of the properties into their own object, then see if that object contains any properties.
const { pageSize, pageStart, page, ...rest } = object;
return Object.keys(rest).length >= 1;
You can use some() testing if any of the Object.keys are not included in an array of expected keys. Here using Set.has() for efficient repeat polling. some() will short-circuit on the first match.
const hasUnexpectedKeys = (obj, expected) => {
const expectedSet = new Set(expected);
return Object.keys(obj).some(k => !expectedSet.has(k));
}
const expected = ['pageSize', 'pageStart', 'page'];
console.log(
hasUnexpectedKeys({ pageStart: 50, page: 2, userName: "Bobby" }, expected)
); // true
console.log(
hasUnexpectedKeys({ pageSize: 4, pageStart: 50, page: 2 }, expected)
); // false
Alternatively with just Array.includes()
const
expected = ['pageSize', 'pageStart', 'page'],
object = { pageStart: 50, page: 2, userName: "Bobby" };
console.log(
Object.keys(object).some(k => !expected.includes(k))
);
Iterate all keys of object (or some) and if you find something not in the whitelist, then raise a flag.
var allowed = "pageStart,page,userName".split(",")
var obj1 = {
page: 2,
pageStart: 2,
hello: 'world'
}
var obj2 = {
page: 2,
pageStart: 2
}
function find_alien(obj) {
for (var key in obj) {
if (allowed.indexOf(key) === -1) {
return key;
}
}
return false;
}
console.log(find_alien(obj1))
console.log(find_alien(obj2))
I have a function in a class definition that returns undefined.
Here is the class:
class Lexer {
// constructor and another method here
make_tokens() {
var tokens = [];
// checking character values here
console.log(tokens);
// Outputs [ Token { type: 'PLUS', value: undefined }, Token { type: 'PLUS', value: undefined } ] if I enter ++
return tokens, null; // returns undefined, null
}
// make_numbers() goes here
}
When I searched for answers, I mainly got returning from asynchronous functions but my function is not asynchronous.
I do not know what the problem is.
(sorry if I didn't structure it well but I am new to StackOverflow and I don't know how to structure a question properly)
Firstly, why you want to return null with other variable but if so then just return an array consisting of 2 elements.
Here's is the code:
class Lexer {
// constructor and another method here
make_tokens() {
var tokens = [];
// checking character values here
console.log(tokens);
// Outputs [ Token { type: 'PLUS', value: undefined }, Token { type: 'PLUS', value: undefined } ] if I enter ++
return [tokens, null] ; // returns undefined, null
}
// make_numbers() goes here
}
But it can be the other way. For eg You want to return null if tokens are not present.
class Lexer {
// constructor and another method here
make_tokens() {
var tokens = [];
// checking character values here
console.log(tokens);
// Outputs [ Token { type: 'PLUS', value: undefined }, Token { type: 'PLUS', value: undefined } ] if I enter ++
return tokens | null; // returns undefined, null
}
// make_numbers() goes here
}
i don't think you could return value that way.
class Lexer {
// constructor and another method here
make_tokens() {
var tokens = [];
// checking character values here
console.log(tokens);
// Outputs [ Token { type: 'PLUS', value: undefined }, Token { type: 'PLUS', value: undefined } ] if I enter ++
return [tokens, null]; // returns undefined, null
}
// make_numbers() goes here
}
const lexer = new Lexer();
console.log(lexer.make_tokens());
You can't return multiple values like that.
I think you end up just returning the last value which in this case is null.
Why do you need to return null aswell?
If you just return tokens it will work.
Just return tokens
class Lexer {
// constructor and another method here
make_tokens() {
var tokens = [];
// checking character values here
console.log(tokens);
// Outputs [ Token { type: 'PLUS', value: undefined }, Token { type: 'PLUS', value: undefined } ] if I enter ++
return tokens; // returns tokens
}
// make_numbers() goes here
}
const lexer = new Lexer();
console.log(lexer.make_tokens());
Let's say you an array of objects, where you're reducing a property into one result separated by dashes, e.g:
const array = [
{ foo: "foo" },
{ foo: "foo" },
]
Should become the string:
foo-foo
If you're using the reduce method, you might do something like this:
const array = [ { foo: "foo" }, { foo: "foo" }, { foo: "foo" } ];
const result = array.reduce( ( accumulator, { foo } ) => {
return accumulator + "-" + foo;
} );
console.log( result );
However, the problem is that the default initial value (the first element of the array) is the entire first object, naturally resulting in [object Object]-foo-foo.
Question is: is there a simple way to, for example destructure, the initial value?
You can bypass the issue by, for example, using an if-statement specifically checking whether the accumulator is currently an object:
const array = [ { foo: "foo" }, { foo: "foo" }, { foo: "foo" } ];
const result = array.reduce( ( accumulator, { foo } ) => {
if ( accumulator.hasOwnProperty( "foo" ) ) {
return accumulator.foo + "-" + foo;
}
return accumulator + "-" + foo;
} );
console.log( result );
However, I am interested in a simpler/prettier way of doing this, using less "arbitrary-looking" code, perhaps a way to do this using the actual initialValue argument of reduce.
Note: I am not looking for an answer to an actual real problem I am facing now (and thus not looking for alternative solutions such as for let/of loops or filtering the array), I am asking for the sake of learning more about the reduce method in these types of situations for future reference.
You could set the initial value to an empty string, and use a ternary to check if the string is empty, if true, then return only the foo, otherwise, return the accumulator, a dash, and foo:
const array = [ { foo: "foo" }, { foo: "foo" }, { foo: "foo" } ];
const result = array.reduce((a, {foo}) => a ? `${a}-${foo}` : foo, '');
console.log(result);
We can be sure that on the initial loop that the ternary will return only foo as '' evaluates to false.
You could map and join the items.
var array = [{ foo: "foo" }, { foo: "foo" }, { foo: "foo" }],
result = array
.map(({ foo }) => foo)
.join('-');
console.log(result);
A reduce approach with a check if a dash is necessary.
var array = [{ foo: "foo" }, { foo: "foo" }, { foo: "foo" }],
result = array.reduce((r, { foo }) => r + (r && '-') + foo, '');
console.log(result);
I'm trying to check the below,
USECASE: 1
var obj = {};
_.isEmpty(obj); ====> returns true
USECASE: 2
var obj = { model: undefined, vendor: undefined, type: undefined }
_.isEmpty(obj); ====> returns false
In usecase 2 is there any other function that i could leverage to return true since all the properties are undefined.
I referred this http://www.ericfeminella.com/blog/2012/08/18/determining-if-an-object-is-empty-with-underscore-lo-dash/ but not sure how to implement it without modifying the native method.
Without Underscore:
const objEmpty = obj => Object.keys(obj).every(key => obj[key] === undefined);
Will accept an object and return true if the object is empty (no properties) or if all the properties have undefined value. Else returns false.
You could use every and pass in the isUndefined predicate:
var obj = { model: undefined, vendor: undefined, type: undefined }
var result = _.every(obj, _.isUndefined);
Alternatively you could omit the undefined values and check whether the object is empty:
var result = _.isEmpty(_.omit(obj, _.isUndefined));
ers,
I'm having some trouble with this algorithm.
I'm using Redux, though I don't think that is really relevant for this problem. Basically the console.log statement in this code returns only one object, just as it should, but the function A returns an array of the two objects (even the one that didn't pass the test in function C)
I separated the functions into 3 parts to see if that would help me fix it, but I couldn't figure it out still.
Any advice?
const A = (state) => {
// looks through an array and passes down a resource
return state.resources.locked.filter((resource) => {
return B(state, resource);
})
};
// looks through an array and passes down a building
const B = (state, resource) => {
return state.bonfire.allStructures.filter((building) => {
return C(building, resource);
})
};
// checks if building name and resource requirment are the same, and if building is unlocked
// then returns only that one
const C = (building, resource) => {
if (building.unlocked && building.name == resource.requires.structure) {
console.log(resource);
return resource;
}
}
When using filter, do realise that the callback functions you pass to it are expected to return a boolean value indicating whether a particular element needs to be filtered in or out.
But in your case, B does not return a boolean, but an array. And even when that array is empty (indicating no resource matches), such a value will not be considered false by filter, and so the corresponding resource will still occur in the array returned by A.
A quick fix: get the length of the array that is returned by B, and return that instead. Zero will be considered false:
const A = (state) => {
// looks through an array and passes down a resource
return state.resources.locked.filter((resource) => {
return B(state, resource).length; /// <---- length!
})
};
// looks through an array and passes down a building
const B = (state, resource) => {
return state.bonfire.allStructures.filter((building) => {
return C(building, resource);
})
};
// checks if building name and resource requirement are the same, and if building
// is unlocked and then returns only that one
const C = (building, resource) => {
if (building.unlocked && building.name == resource.requires.structure) {
return resource;
}
}
// Sample data. Only x matches.
var state = {
resources: {
locked: [{ // resource
requires: {
structure: 'x'
}
}, { // resource
requires: {
structure: 'y'
}
}]
},
bonfire: {
allStructures: [{ // building
unlocked: true,
name: 'x'
}, { // building
unlocked: true,
name: 'z'
}]
}
};
console.log(A(state));
But better would be to really return booleans at each place where they are expected. So C should just return the result of the condition, and B could use some instead of filter, which not only returns a boolean, but also stops looking further once a match is found. In A you can have the original code now, as you really want A to return data (not a boolean).
Note also that you can use the short-cut notation for arrow functions that only have an expression that is evaluated:
// looks through an array and passes down a resource
const A = state => state.resources.locked.filter( resource => B(state, resource) );
// looks through an array and passes down a building
// Use .some instead of .filter: it returns a boolean
const B = (state, resource) =>
state.bonfire.allStructures.some( building => C(building, resource) );
// checks if building name and resource requirment are the same, and if building
// is unlocked and then returns only that one
// Return boolean
const C = (building, resource) => building.unlocked
&& building.name == resource.requires.structure;
// Sample data. Only x matches.
var state = {
resources: {
locked: [{ // resource
requires: {
structure: 'x'
}
}, { // resource
requires: {
structure: 'y'
}
}]
},
bonfire: {
allStructures: [{ // building
unlocked: true,
name: 'x'
}, { // building
unlocked: true,
name: 'z'
}]
}
};
console.log(A(state));