I've been playing around with reducers in this years's first advent of code challenge, and this code works fine:
export default class CalorieCounter {
public static calculateMaxInventoryValue(elfInventories: number[][]): number {
const sumInventoriesReducer = (
acc: number[],
element: number[]
): number[] => [...acc, this.sumCalories(element)];
return Math.max(...elfInventories.reduce(sumInventoriesReducer, []));
}
private static sumCalories(inventory: number[]): number {
return inventory.reduce((a: number, b: number) => a b, 0);
}
}
I then tried to split out the sumInventoriesReducer into it's own private function in the same class. This code does not work:
export default class CalorieCounter {
public static calculateMaxInventoryValue(elfInventories: number[][]): number {
return Math.max(...elfInventories.reduce(this.sumInventoriesReducer, []));
}
private static sumInventoriesReducer(
acc: number[],
element: number[]
): number[] {
return [...acc, this.sumCalories(element)];
}
private static sumCalories(inventory: number[]): number {
return inventory.reduce((a: number, b: number) => a b, 0);
}
}
The logic is exactly the same, all that's changed is that it's passed in as a private function (the fact that it's static isn't the reason, tried it without static and got the same error).
This is the error:
TypeError: Cannot read property 'sumCalories' of undefined
20 | element: number[]
21 | ): number[] {
> 22 | return [...acc, this.sumCalories(element)];
| ^
23 | }
24 |
25 | private static sumCalories(inventory: number[]): number {
I want to do this in an OOP way if I can, aware reducers are a staple of functional programming but I feel like I should be able to get this work using a private class function. Can anyone help?
CodePudding user response:
The problem is that you're trying to access an instance property (that exist only after constructor()
has been called) in a static method (that exists only on the class and not on the prototype).
After a constructor()
method has been called the keyword this
has the value of the instance
object, but if you reference this
in a static method you're referencing an undefined variable since to access a static method you don't call a constructor method
export default class CalorieCounter {
public static calculateMaxInventoryValue(elfInventories: number[][]): number {
return Math.max(...elfInventories.reduce(this.sumInventoriesReducer, []));
}
private static sumInventoriesReducer(
acc: number[],
element: number[]
): number[] {
return [...acc, this.sumCalories(element)]; // The problem is here
}
private static sumCalories(inventory: number[]): number {
return inventory.reduce((a: number, b: number) => a b, 0);
}
}
If you want to keep this schema you can just update that line so it would go
- from:
this.sumCalories(element)
- to:
CalorieCounter.sumCalories(element)
By doing so, you're accessing the method from the class itself and not from a non-existing instance.
The resulting code would be:
export default class CalorieCounter {
public static calculateMaxInventoryValue(elfInventories: number[][]): number {
return Math.max(...elfInventories.reduce(this.sumInventoriesReducer, []));
}
private static sumInventoriesReducer(
acc: number[],
element: number[]
): number[] {
return [...acc, CalorieCounter.sumCalories(element)]; // The problem is here
}
private static sumCalories(inventory: number[]): number {
return inventory.reduce((a: number, b: number) => a b, 0);
}
}
Same as above, also the calculateMaxInventoryValue
method is static but tries to access an instance method, by correcting it the code would become:
export default class CalorieCounter {
public static calculateMaxInventoryValue(elfInventories: number[][]): number {
return Math.max(...elfInventories.reduce(CalorieCounter.sumInventoriesReducer, []));
}
private static sumInventoriesReducer(
acc: number[],
element: number[]
): number[] {
return [...acc, CalorieCounter.sumCalories(element)]; // The problem is here
}
private static sumCalories(inventory: number[]): number {
return inventory.reduce((a: number, b: number) => a b, 0);
}
}
CodePudding user response:
This is because you don't flatten this.sumCalories(element)
.
this.sumCalories(element)
returns a number[]
, so you need to flatten this with the three dots.
If you write return [...acc, ...this.sumCalories(element)];
it should work.