0

I'm trying convert one method to generic method to use with arrow function in JavaScript, but somehow not able to figure how should I convert it. groupBy: <Map>(predicate: (item: T) => Map[]) => Map[];

Array.prototype.groupBy = function (predicate) {
return this.reduce(
    (entryMap, e) => entryMap.set(e.status, [...entryMap.get(e.status) || [], e]),
    new Map()
)};

Predicate which I'm receiving in this method is like ƒ (x) { return x.status; }.

I want to replace this e.status to with some generic so I can use it like arrayData.groupBy(x=>x.status). As a beginner, I'm not able to figure out how I should do this. I found method in a post @ https://stackoverflow.com/a/47752730/5001462, posted by @Arthur Tacca

Thanks in advance

DigguDg
  • 19
  • 1
  • 10

1 Answers1

1

The code from the linked question is grouping the objects based on e.status. But, in your case the property is dynamic. If you pass x => x.status as the predicate argument, how do you get the e.status for each object in reduce? You just need to call the predicate with the e parameter. So, replace all e.status with predicate(e)

Array.prototype.groupBy = function(predicate) {
  return this.reduce(
    (entryMap, e) => entryMap.set(predicate(e), [...entryMap.get(predicate(e)) || [], e]),
    new Map()
  )
};

const arr = [{ status: 10, id: 1 }, { status: 10, id: 2 }, { status:20, id: 3 }],
      map = arr.groupBy(e => e.status)

console.log(map.get(10))
console.log(map.get(20))
console.log(map.get(30))

Please note that extending native objects a bad practice. Even if you add new items to the prototypes, make sure you add using Object.defineProperty like this:

Object.defineProperty(Array.prototype, "groupBy", {
  value: function(predicate) {
    return this.reduce(
      (entryMap, e) => entryMap.set(predicate(e), [...entryMap.get(predicate(e)) || [], e]),
      new Map()
    )
  },
  configurable: true,
  writable: true
});

If you define it this way, enumerable will be set to false. If you directly add Array.prototype.groupBy = function(predicate){}, enumerable will be set to true, it will show up in for..in loops.

adiga
  • 34,372
  • 9
  • 61
  • 83
  • 1
    You'd probably want to provide `writable: true` and `configurable: true` just to maintain consistency with how classes define prototype methods. Also if you're going to get that detailed, I'd suggest using `Array.prototype.reduce.call(this, ...)` instead of `this.reduce(...)`, to not name the callback `predicate` since it's not a predicate, and to consider calling it once per iteration instead of twice in case it's an expensive computation. – Patrick Roberts Sep 04 '20 at 13:51
  • @PatrickRoberts I rechecked Array method polyfills on MDN. Some do have `writable` and `configurable` set to `true`, but some don't. Some have parameter name as `func` but some call it `predicate`. There's no consistency there. I think it makes sense to add `writable` and `configurable` to the methods. – adiga Sep 04 '20 at 14:16
  • MDN is not the spec. Don't rely on documentation for naming conventions, refer directly to the specification in that case. As for the array methods that don't set the `writable` and `configurable` flags, can you provide any references? – Patrick Roberts Sep 04 '20 at 14:20
  • @PatrickRoberts Sorry, I can't read. I had checked [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every#Polyfill) and [`every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every#Polyfill) to see if they have `configurable` at the end. I just realized they aren't even using `Object.defineProperty` in those 2 methods. – adiga Sep 04 '20 at 16:19