skip to Main Content

I’m trying to use reduce to create an object that contains the percentage of presence of various countries in a list.

input:

countriesList = ["US","US","US","UK","IT","IT"]

desidered output:

percCountriesList = [{"country": "US", "weight": 0.5}, {"country": "UK", "weight": 0.1666}, {"country": "IT", "weight": 0.3333}]

How I calculate the percentage:

const countriesList = ["US","US","US","UK","IT","IT"]
const weightPercCountries = countriesList.reduce((pcts, x) => {
    pcts[x] = (pcts, (pcts[x] ? pcts[x] : 0) + 100 / countriesList.length);
    return pcts;
}, []);
console.log(weightPercCountries)

So, I’ve got the percentages list:

[50, 16.666666666666668, 33.33333333...]

Now, how I can build the desidered output (country + weight) "jsonized"?
Thanks

2

Answers


  1. const countriesList = ["US","US","US","UK","IT","IT"]
    
    const r = Object.values(countriesList.reduce((a,c,_,r)=>
      ((a[c]??={'country':c, weight:0}).weight+=1/r.length,a),{}))
    
    console.log(r)

    The code above uses the ??= operator to set a property if the property is not yet defined, and uses a comma expression to avoid the need for a braced code block ending with with return a.

    A less compact version of the code is:

    const countriesList = ["US","US","US","UK","IT","IT"]
    
    const m = countriesList.reduce((a,c,_,r)=> {
      if (!a[c]) a[c] = {'country': c, weight: 0}
      a[c].weight += 1 / r.length
      return a
    }, {})
    
    // produces:
    // {
    //   US: { country: 'US', weight: 0.5 },
    //   UK: { country: 'UK', weight: 0.16666666666666666 },
    //   IT: { country: 'IT', weight: 0.3333333333333333 }
    // }
    
    // now take just the object values, and not the keys
    const r = Object.values(m)
    
    console.log(r)
    Login or Signup to reply.
  2. First of all, your code produces an empty array (with a few additional properties), because the x in your case is a country-shortcut and not an index. So if you do pcts[x] = .. you are actually doing something like pcts['us'] = ... which in most cases doesn’t make too much sense for an array.

    Second, if you want a complex object in you array, you need to create it somewhere … See for instance the following snippet

    1. I defined reduce to return an object, so I can easily check if the current country (defined by x) is already contained or not.

    2. If it’s not contained, I add a new property to the object, which already holds all properties I want in the result (ie { country: x, percentage: 0})

    3. Now, that I made sure, an object for the current country exists, I can access it via its name and update the percentage. Whether you want 50 or 0.5 is up to you. Either use 100/countriesList.length or 1/countriesList.length

    4. reduce now returns an object like

       {
         "us": { country: "us", percentage: 0.5},
         "it": { country: "it", percentage: 0.33} 
         ...
       }
      

      So to get an array of the values just use Object.values(...) which returns all enumerable properties of an object as an array

    const 
      countriesList = ["US","US","US","UK","IT","IT"];
      
    
    const 
      weightPercCountries = Object.values(countriesList.reduce((pcts, x) => {
        if (!(x in pcts))
          pcts[x] = { country: x, percentage: 0}
        
        pcts[x].percentage += (1 / countriesList.length);
        return pcts;
    }, {}));
    
    console.log(weightPercCountries)

    Of course you can shorten the callback of the reduce (like for instance in Andrew Park’s answer). But for sake of readability (especially for someone who seems to be a beginner) I decided in favour of the more explicit code …

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search