const is undefined within reduce method - javascript

avgPrice(data) {
const min_price = data.min_price,
max_price = data.max_price;
console.log(min_price) //has value
let x = _.reduce(data.custom_pricing, (a, b) => {
a.min_price = Math.min(a.min_price, b.min_price);
a.max_price = Math.max(a.max_price, b.max_price);
}, { min_price:min_price, max_price:max_price });
}
What's wrong with my code above? I got min_price is undefined error. But my const min_price has value when I do console.log.

You have to return from reduce (return a so it can be used for the next iteration).
let x = _.reduce(data.custom_pricing, (a, b) => {
a.min_price = Math.min(a.min_price, b.min_price);
a.max_price = Math.max(a.max_price, b.max_price);
return a; //<<<<<
}, { min_price:min_price, max_price:max_price });
No mutation:
Although I don't see a reason why.
let x = _.reduce(data.custom_pricing, (a, b) =>
({ min_price: Math.min(a.min_price, b.min_price), max_price: Math.max(a.max_price, b.max_price) }), // create a new object and return it
{ min_price:min_price, max_price:max_price });

Related

Looping data from json using Array

I'm trying to write a function but I doesn't make it. This function works like that
Input: changeSetting("a>b>c","hello")
After that "setting" named value change from {} to {"a":{"b":{"c":"hello"}}}
If input is changeSetting("a","hello") json become {} to {"a":"hello"}
My last code attempt:
function changeSetting(name,val) {
if (name.includes(">")) {
name = name.split('>')
let json = {}
name.map((el,i)=>{
let last = ""
name.filter(el=>!name.slice(i+1).includes(el)).map(el=> {
if(last!="") {
json[el] = {}
}})
})
}
}
How can we make this ? (Optimization not important but if is it good for me)
const changeSetting = (setting, target) => {
if (setting.length < 2) {
return {
[setting]: target
}
} else {
const keys = setting.split('>');
return keys.reduceRight((acc, curr, i) => {
console.log(acc);
if(i === keys.length - 1) {
return acc = {[curr] : target}
}
return acc = { [curr]: acc };
}, {})
}
}
console.log(changeSetting('a', 'hello'));
console.log(changeSetting('a>b>c', 'hello'));
function changeSetting(inputProperties, value) {
let result;
const properties = inputProperties.split(">");
result = `{${properties
.map((property) => `"${property}":`)
.join("{")}"${value}"${"}".repeat(properties.length)}`;
return result;
}
changeSetting("a>b>c", "hello");
changeSetting("a", "hello");
As you work with strings - you may try to use JSON like this:
function changeSetting(name, val) {
const keys = name.split(">");
return JSON.parse(
[
"{",
keys.map((key) => `"${key}"`).join(":{"),
":",
`"${val}"`,
"}".repeat(keys.length),
].join("")
);
}
There's multiple ways to do this, I've commented the snippet
const changeSetting = (name, val) => {
// Split and reverse the name letters
const nameSplit = name.split('>').reverse();
// Set up the inner most object
let newObj = {[nameSplit[0]]:val}
// Now remove the first letter and recurse through the rest
nameSplit.slice(1).forEach((el, idx) => newObj = {[el]: newObj});
console.log(newObj);
}
changeSetting("a>b>c", "hello")
changeSetting("a", "hello")
changeSetting("a>b>c>d>e>f>g", "hello")
You can create an array by splitting name on all > with String.prototype.split(), and then Array.prototype.reduceRight() the created array of elements with an object initial value {} and adding key value pairs but on the last element the value should be variable val.
Code:
const changeSetting = (name, val) => name
.split('>')
.reduceRight((a, c, i, arr) => ({
[c]: i === arr.length - 1 ? val : a
}), {})
console.log(changeSetting('a>b>c', 'hello'))
console.log(changeSetting('a', 'hello'))
console.log(changeSetting('a>b>c>d>e>f>g', 'hello'))

Write a higher-order function, checkConsistentOutput()

This function should have two parameters: a function and a value. It should call the argument function with the value two times. If the callback function produces the same result twice, it should return the result of the function call, otherwise, it should return the string 'This function returned inconsistent results'
const checkThatTwoPlusTwoEqualsFourAMillionTimes = () => {
for(let i = 1; i <= 1000000; i++) {
if ( (2 + 2) != 4) {
console.log('Something has gone very wrong :( ');
}
}
};
const addTwo = num => num + 2;
const timeFuncRuntime = funcParameter => {
let t1 = Date.now();
funcParameter();
let t2 = Date.now();
return t2 - t1;
};
// Write your code below
const time2p2 = timeFuncRuntime(checkThatTwoPlusTwoEqualsFourAMillionTimes);
const checkConsistentOutput(func, val) => {
let checkOne = func(val);
let checkTwo = func(val);
if (checkOne === checkTwo){
return checkOne;
} else {
return 'This function returned inconsisent results'
}
}
I'm getting the error SyntaxError: Missing initializer in const declaration. please help me understand.
I'm seeing an error in the last const declaration that appears to be because it's missing an '='.
const checkConsistentOutput(func, val) => {
...
}
const checkConsistentOutput = (func, val) => {
...
}

returning object that returns functions

I need to write a function in JavaScript that takes a number and returns an object that returns chainable functions (without using OOP).
Example:
func(3).not().not().equals(4)
would outputs false.
And:
func(5).equals(5)
would output: true
This is the code I have written:
const func = (obj) => {
const obj2 = {
not: () => {
return !obj
},
equals: (num) => {
return obj === num
}
}
return obj2
}
It works when I call func(3).not() or func(5).equals(5), but doesn't allow me to chain the functions so calling func(5).not().equals(5) returns an error saying that this is not a function.
What am I not seeing here?
That's a very weird way to compose functions. Let's think about what's actually happening.
func(3).not().not().equals(4)
// is equivalent to
not(not(equals(4)(3)))
// where
const not = x => !x;
const equals = x => y => x === y;
The simplest way to implement this chain would be as follows.
const equals = x => toBool(y => x === y);
const toBool = func => ({
not: () => toBool(x => !func(x)),
func
});
const example1 = equals(4).not().not().func(3);
const example2 = equals(5).func(5);
console.log(example1); // false
console.log(example2); // true
However, this is a forward chain. You want a backward chain. Unfortunately, there's a problem.
In a forward chain .func(x) marks the end of the chain.
In a backward chain .equals(x) marks the end of the chain.
This means that in a backward chain, you wouldn't be able to write the following expression.
func(3).not().not().equals(4).add(1)
// expected to be equivalent to
not(not(equals(4)(add(1)(3))))
// but actually equivalent to
not(not(equals(4)(3))).add(1)
// which evaluates to
false.add(1)
On the other hand, you would be able to do this quite easily using a forward chain.
const id = x => x;
const toNum = func => ({
add: x => toNum(y => x + func(y)),
equals: x => toBool(y => x === func(y)),
func
});
const toBool = func => ({
not: () => toBool(x => !func(x)),
func
});
const { add, equals } = toNum(id);
const example1 = equals(4).not().not().func(3);
const example2 = add(1).equals(4).not().not().func(3);
console.log(example1); // false
console.log(example2); // true
By the way, this is an object-oriented design pattern even though it doesn't make use of classes.
My advice would be to write plain old functions.
const add = (x, y) => x + y;
const equals = (x, y) => x === y;
const not = x => !x;
const example1 = not(not(equals(4, 3)));
const example2 = not(not(equals(4, add(1, 3))));
console.log(example1); // false
console.log(example2); // true
The simplest solutions are usually the best. Source: Occam's razor.
To return another object with the same methods that wraps the new value, simply call func again:
const func = (obj) => {
const obj2 = {
not: () => {
return func(!obj)
// ^^^^^^^^^^^^^^^^^
},
equals: (num) => {
return obj === num
}
}
return obj2
}
console.log(func(3).not().not().equals(4))
console.log(func(5).equals(5))
console.log(func(3).not())
You can use a closure to store both the initial input and the state of the operation:
const func = (input) => {
let not = false
const obj = {
not: () => {
not = !not
return obj
},
equals: (num) => {
return not ? input !== num : input === num
}
}
return obj;
}
console.log(func(5).not().equals(5))
console.log(func(5).not().not().equals(5))
console.log(func(5).not().equals(4))
console.log(func(5).not().not().equals(4))
You could take an object for return as interface and store value and negation.
var object = {
func: function (value) {
object.left = value;
return object;
},
not: function() {
object.negation = !object.negation;
return object;
},
equals: function (value) {
var result = value === object.value;
return object.negation ? !result : result;
}
},
func = object.func;
console.log(func(3).not().not().equals(4));

abstract javascript code into ES6 function

I have some code that is working but I want to abstract it into a functional component I can use elsewhere in my script. I am getting an undefined error:
This works:
//add an index to each element
var items = learning_check.map(function(el,i) {
var o = Object.assign({}, el);
o.key = i;
return o;
});
this doesn't:
const addIndex = (a) => {
console.log('addIndex initiated')
a.map = (el,i) => {
var o = Object.assign({}, el);
o.key = i;
return o;
}
}
called with
const mItems = addIndex(learning_check); // initiated
console.log('mItems: ' + mItems); // undefined
Firstly, I'd like to say that you're on the right track. You're missing two things.
You need to call map and not reassign it, like a.map(...) and not a.map = .... And, you need to return the result of map from your addIndex function. Like so,
const addIndex = (a) => {
console.log('addIndex initiated');
// Notice the return
return a.map((el, i) => { // See how we call map here
var o = Object.assign({}, el);
o.key = i;
return o;
});
}
// Mock
const learning_check = [{
id: "abcde"
}, {
id: "fghij"
}];
const mItems = addIndex(learning_check); // initiated
console.log('mItems: ' + JSON.stringify(mItems));
I'll suggest a simplification to your code here, you could use it if you like
const addIndex = (a) => {
console.log('addIndex initiated')
return a.map((el, i) => Object.assign({
key: i
}, el));
}
// Mock
const learning_check = [{
id: "abcde"
}, {
id: "fghij"
}];
const mItems = addIndex(learning_check); // initiated
console.log('mItems: ' + JSON.stringify(mItems));
Two bugs in your code
1) You are not returning anything from the function.
2) You are not calling the map function.
const addIndex = (a) => {
console.log('addIndex initiated')
return a.map((el, i) => {
var o = Object.assign({}, el);
o.key = i;
return o;
})
}

Merge 2 arrays of objects setting key from one and value from the other

I have 2 objets a and b defined as the following :
a = {
1:3,
2:5,
3:1,
}
b = {
1:{name:"Bob"},
2:{name:"John"},
3:{name:"Alice"}
}
What I am trying to get is the following object c defined as
c = {
"Bob":3,
"John":5,
"Alice":1
}
So creating an using b[key].name as c[key] and a[key] as value.
What I tried so far is
const mapAandB = (a, b) => {
let finalObject = [];
Object.keys(b).forEach(key => {
return finalOdds.push({ [b[key].name]: a[key] });
});
return finalOdds;
};
but then the result is
c = [
0:{Bob:3},
1:{John: 5},
2:{Alice:1}
]
If you have any suggestion ...
You can use Array#reduce to collect the names and values into an object:
const a = {"1":3,"2":5,"3":1}
const b = {"1":{"name":"Bob"},"2":{"name":"John"},"3":{"name":"Alice"}}
const result = Object.keys(a).reduce((r, key) => {
r[b[key].name] = a[key];
return r;
}, {});
console.log(result);
Or you can use Array#map to create a series of objects, and combine them to one using Object#assign and spread:
const a = {"1":3,"2":5,"3":1}
const b = {"1":{"name":"Bob"},"2":{"name":"John"},"3":{"name":"Alice"}}
const result = Object.assign(...Object.keys(a).map((key) => ({ [b[key].name]: a[key] })));
console.log(result);
Try this solution. If you want to get an object instead of array, just add the result into the Object.assign(...result)
const a = {
1:3,
2:5,
3:1,
}
const b = {
1:{name:"Bob"},
2:{name:"John"},
3:{name:"Alice"}
}
const mapAandB = (a, b) => Object.keys(a).map(key => ({[b[key].name]: a[key]}));
console.log(mapAandB(a,b));

Categories