0

I need to display the countries with the most users. In order from largest to smallest (and additionally max 10 countries). How can I achieve it?

let users = {
                    1: {
                        name: "Name1",
                        country: "US",
                    },
                    2: {
                        name: "Name2",
                        country: "US",
                    },
                    3: {
                        name: "Name3",
                        country: "FR",
                    },
                    4: {
                        name: "Name4",
                        country: "DE",
                    },
                };

groupBy(users, "country", "asc")

And I get an array like:

{
   DE: array(),
   US: array(),
   FR: array()
}

How can I sort this data? I need to return the number of users by country. I would like to receive something like this:

{
   US: 2
   DE: 1,
   FR: 1
}

I am using some Lodash functions (imports them one at a time)

kamilon123s
  • 323
  • 1
  • 7
  • Please post a minimal reproducible example: https://stackoverflow.com/help/minimal-reproducible-example – Rohit Kashyap Jan 24 '21 at 13:20
  • You have an object and not an array which is not sortable, (though it does now follow predictable ordering of its properties, see: [Does JavaScript guarantee object property order?](https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order) – pilchard Jan 24 '21 at 13:32

3 Answers3

1

Just in case anybody should be interested: here is another solution without lodash:

users = {  0: { name: "Name4", country: "DE", },
1: { name: "Name1", country: "US", }, 2: { name: "Name2", country: "US", }, 3: { name: "Name3", country: "FR", } };

res=Object.values(users).reduce((a,c)=>
((a[c.country]=1+a[c.country]||1),a), {});

console.log("unordered:",res);

// strictly speaking Objects cannot be sorted, however:
// many browsers preserve
// the order in which properties were generated:
console.log("ordered:",Object.fromEntries(Object.entries(res).sort((a,b)=>b[1]-a[1])));

Update

Only after this answer was briefly the "accepted" one I realized that I didn't address the part of the question concerned with ordering. Strictly speaking objects cannot be sorted and do not have a "guaranteed" order, but have a look at the snippet: in many cases (i.e. in several browsers) an "order" can be established nonetheless by adding properties to it in a certain order.

Carsten Massmann
  • 16,701
  • 2
  • 16
  • 39
1

Create a counter object, then sort it.

let users = {
  1: {
      name: "Name1",
      country: "US",
  },
  2: {
      name: "Name2",
      country: "US",
  },
  3: {
      name: "Name3",
      country: "FR",
  },
  4: {
      name: "Name4",
      country: "DE",
  },
  5: {
      name: "Name5",
      country: "DE",
  },
  6: {
      name: "Name6",
      country: "DE",
  }
};

const counter = {
};

for(const user of Object.keys(users)) {
    if(counter.hasOwnProperty(users[user].country)) {
        counter[users[user].country] += 1;
    } else {
        counter[users[user].country] = 1
    }
}

let counterArr = Object.keys(counter).map(function(key) {
    return [key, counter[key]];
});

counterArr.sort((a, b) => {
    return b[1] - a[1];
});

console.log(counterArr);

You can then just display the first 10

Gary
  • 172
  • 10
  • 1
    The counting part works fine but your sorting part does not do anything. Presenting an object in a prescribed order is a doubtful exercise in the first place (see my post below), but simply ordering the `counter` keys alphabetically will not have any effect on the output of object `output`. – Carsten Massmann Jan 24 '21 at 14:56
  • You're right, I was thinking about sorting an array of objects this way. I would delete this but can't because it's accepted – Gary Jan 24 '21 at 15:24
  • :D @Gary, no sweat - I just wanted to make it clear to future readers! – Carsten Massmann Jan 24 '21 at 16:28
  • 1
    @cars10m I have edited it now so it is a working answer although probably not the best solution. – Gary Jan 24 '21 at 16:43
0

You could _.mapValues to map the object through it's values and for each value, get the length of array with _.size

All these thing could be chaining if you are like one-liner statement

let users = {
  1: {
    name: "Name1",
    country: "US",
  },
  2: {
    name: "Name2",
    country: "US",
  },
  3: {
    name: "Name3",
    country: "FR",
  },
  4: {
    name: "Name4",
    country: "DE",
  },
};

const res = _
  .chain(users)
  .groupBy("country", "asc")
  .mapValues(_.size)
  .value();

console.log(res);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"></script>
hgb123
  • 9,840
  • 3
  • 11
  • 31