1

I have an array of pokemon objects which have a Max and Min height (see snapshot below) and I need to return the average minimum and maximum height for all pokemon in the form of a tuple

const allPokemon = [
  {
    Height: {
      Minimum: '0.61m',
      Maximum: '0.79m',
    },
  },
];

I need to use HOFs so I was thinking to do something like this for both Maximum and Minimum height:

allPokemon.reduce((acc, cur) => acc + parseInt(cur.Height.Maximum), 0) / allPokemon.length;
allPokemon.reduce((acc, cur) => acc + parseInt(cur.Height.Minimum), 0) / allPokemon.length;

but I'm not sure how to return the two values in the form of a tuple (create empty array and push the values in? Concat method?)

Any help would be much appreciated.

Ali Esmailpor
  • 1,209
  • 3
  • 11
  • 22
ruggle
  • 109
  • 1
  • 5

4 Answers4

3

For now, JavaScript doesn’t have tuples. Besides, Javascript is weakly typed

Weakly typed means the compiler, if applicable, doesn't enforce correct typing. Without implicit compiler interjection, the instruction will error during run-time.

However, with the object or array destructuring you can archive it

  1. You can use .reduce with initial data as object like { Maximum: 0, Minimum: 0 } to aggregate your data like below:

const allPokemon = [
        {
          Height: {
            Minimum: "1.61m",
            Maximum: "2.79m"
           }
        }]
        
var result = allPokemon.reduce((acc, cur) => {
      acc.Maximum += (parseFloat(cur.Height.Maximum)/allPokemon.length);      
      acc.Minimum += (parseFloat(cur.Height.Minimum)/allPokemon.length);
      
      return acc; 
}, { Maximum: 0, Minimum: 0 });

console.log(result);
  1. The second way is using array then destructuring assignment like this

const allPokemon = [
        {
          Height: {
            Minimum: "1.61m",
            Maximum: "2.79m"
           }
        }]
        
var result = allPokemon.reduce((acc, cur) => {
      acc[0] += (parseFloat(cur.Height.Maximum)/allPokemon.length);      
      acc[1] += (parseFloat(cur.Height.Minimum)/allPokemon.length);
      
      return acc; 
}, [0, 0]);

console.log(result);

// Array Destructuring here
const [Maximum, Minimum] = result;
console.log("Maximum: " + Maximum);
console.log("Minimum: " + Minimum);

For example:

const [a, b] = [10, 20]; // a = 10, b= 20

Note: As @VLAZ 's comment, in the near future we'd have proper tuples and records like this one proposal-record-tuple

Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56
  • @Phong Mostly yes thank you! How would I implement the allPokemon.length within the code itself rather than in the console.log? – ruggle Jan 22 '21 at 10:14
  • It depends on your logic, you can also move `/allPokemon.length` into individual calculating like `acc.Maximum += (parseFloat(cur.Height.Maximum)/allPokemon.length)`. But it should move out to calculate average :) @ruggle – Nguyễn Văn Phong Jan 22 '21 at 10:16
  • I need it to return as an array with the two values i.e. [1,61, 2.79] – ruggle Jan 22 '21 at 10:18
  • Of course, you can use `the second solution` with `destructuring assignment` : @ruggle – Nguyễn Văn Phong Jan 22 '21 at 10:19
  • 1
    ahh, didn't see that one! Thanks for your help! I wasn't aware of the array destructuring technique. I'll need to read upon it! – ruggle Jan 22 '21 at 10:21
  • 2
    "*No, JavaScript doesn’t have tuples (Because javascript weakly typed)*" being weakly typed doesn't have any bearing on having tuples or not. Weakly typed means that conversions can happen. That doesn't mean types don't exist - there are already numbers and strings, among others. A tuple can just be another type and [indeed there is a proposal for it](https://github.com/tc39/proposal-record-tuple). Hopefully in the near future we'd have proper tuples and records (basically named tuples). – VLAZ Jan 22 '21 at 10:23
3

const allPokemon = [
        {
          Height: {
            Minimum: "1.61m",
            Maximum: "2.79m"
           }
        }]
        
const [avgMin, avgMax] = allPokemon.reduce((acc, cur) => {
      acc[0] += parseFloat(cur.Height.Minimum);      
      acc[1] += parseFloat(cur.Height.Maximum);
      
      return acc; 
}, [0, 0]).map(total => total / allPokemon.length)

console.log(`Average min: ${avgMin}\nAverage max: ${avgMax}`);

The first value of the result tuple is the average minimum and the second is the average maximum.

ecoplaneteer
  • 1,918
  • 1
  • 8
  • 29
1

There's no tuple in JavaScript, you may return an array instead. JS will unpack into variables.

function foo(){
    return ["value1","value2"];
}

[var1,var2] = foo();
console.log(var1,var2);
Dee
  • 7,455
  • 6
  • 36
  • 70
0

I don't think you need hof (look at others answers) however if you really want to use hof (e.g as an exercise) you need a function which takes a function as parameter

So e.g

take a function which extracts the numerical property and take a function which uses it to average the data.

function getValue(pokemon) {
  return pokemon.height.Maximum
}

function avgBy(getValue, pokemons) {
  return pokemons.length === 0 ? 0 : pokemons.reduce((s, p) => s + getValue(p), 0) / pokemons.length
}

Then you can indeed compose:

function getMin (pokemon) { return pokemon.height.Minimum }
function getMax (pokemon) { return pokemon.height.Maximum }
const [min, max] = [avgBy(getMin, pokemons), avgBy(getMax, pokemons)]

The nice property is now you have the avgBy which can compute the avg of whatever as long you give it a proper getValue func

function getMin (pokemon) { return pokemon.height.Minimum }
function getMax (pokemon) { return pokemon.height.Maximum }

function avgBy(getValue, pokemons) {
  return pokemons.length === 0 ? 0 : pokemons.reduce((s, p) => s + getValue(p), 0) / pokemons.length
}
const pokemons = [{height:{Maximum: 1, Minimum: 0}}, {height:{Maximum: 3, Minimum:1}}]
const [min, max] = [avgBy(getMin, pokemons), avgBy(getMax, pokemons)]
console.log({min, max})
grodzi
  • 5,633
  • 1
  • 15
  • 15