1

What is the alternative/best way to map through an object key-values without using forEach?

This is what I have currently:

sortObject(source) {
    const object = Object.assign({}, source);

    Object.keys(object).forEach(key => {
      // Sort array by priority (the higher the number, the higher the priority)
      object[key] = object[key].sort((a, b) => b.priority - a.priority);

      // Limit the array length to the 5
      if (object[key].length > 5) {
        object[key] = object[key].slice(0, 5);
      }
    });

    return object;
}

source is an object like:

{
  base: [
    { id: 1, priority: 5 },
    { id: 2, priority: 10 },
    { id: 3, priority: 1 },
    { id: 4, priority: 5 },
    { id: 5, priority: 15 }
  ],
  extra: [
    { id: 1, priority: 1 },
    { id: 2, priority: 5 },
    { id: 3, priority: 10 }
  ],
  additional: [
    { id: 1, priority: 5 },
    { id: 2, priority: 10 },
    { id: 3, priority: 10 },
    { id: 4, priority: 15 },
    { id: 5, priority: 1 },
    { id: 6, priority: 29 },
    { id: 7, priority: 100 },
    { id: 8, priority: 100 },
    { id: 9, priority: 5 }
  ]
}

The final output is like:

{
  base: [
    { id: 5, priority: 15 },
    { id: 2, priority: 10 },
    { id: 1, priority: 5 },
    { id: 4, priority: 5 },
    { id: 3, priority: 1 }
  ],
  extra: [
    { id: 3, priority: 10 },
    { id: 2, priority: 5 },
    { id: 1, priority: 1 }
  ],
  additional: [
    { id: 7, priority: 100 },
    { id: 8, priority: 100 },
    { id: 6, priority: 29 },
    { id: 4, priority: 15 },
    { id: 2, priority: 10 }
  ]
}

is there a better/cleaner way to do this?

4
  • 1
    Can you give an example of the actual input, rather than placeholder empty objects, so we have a minimal reproducible example to play with? Commented Oct 11, 2018 at 8:25
  • @CertainPerformance sure! give me a second Commented Oct 11, 2018 at 8:25
  • You can use for...in Commented Oct 11, 2018 at 8:29
  • Also, note that sort works in place, so no need for object[key] = object[key].sort(...). And any time you find yourself repeating something like object[key] over and over, it suggests you might want to put it in a variable and reuse it. Commented Oct 11, 2018 at 8:29

2 Answers 2

3

I'd look at Object.entries (new as of ES2017 but polyfillable) and destructuring in a for-of loop.

If nothing else has access to the arrays on source (which I tend to assume, since sort works in-place, so the code already modifies the original array; but at the same time, source is coming in from outside, so...):

sortObject(source) {
    const object = Object.assign({}, source);

    for (const [key, array] of Object.entries(object)) {
        array.sort((a, b) => b.priority - a.priority);
        array.length = Math.min(array.length, 5);
    }

    return object;
}

If something else has access to those arrays and you shouldn't modify them other than sorting them, then you'll need your original length check and slice:

sortObject(source) {
    const object = Object.assign({}, source);

    for (const [key, array] of Object.entries(object)) {
        array.sort((a, b) => b.priority - a.priority);
        if (array.length > 5) {
            object[key] = array.slice(0, 5);
        }
    }

    return object;
}

Your code suggests you may not have realized sort works in-place since you were assigning the result back to the original location. If so and you didn't intend to sort the arrays in-place, you'll need to copy the arrays before sorting:

sortObject(source) {
    const object = Object.assign({}, source);

    for (const [key, array] of Object.entries(object)) {
        object[key] = array = array.slice();
        array.sort((a, b) => b.priority - a.priority);
        array.length = Math.min(array.length, 5);
    }

    return object;
}

You could replace

        object[key] = array = array.slice();
        array.sort((a, b) => b.priority - a.priority);

with

        object[key] = array = Array.from(array).sort((a, b) => b.priority - a.priority);

if you like, but that'll use an iterator, which is more overhead than slice.

Sign up to request clarification or add additional context in comments.

Comments

0

You can also use map for looping the object entries and splice for cutting off the array length:

const getSortedObj = (source) => {
    let obj = Object.assign({}, source);
    Object.entries(obj).map( entry => {
        let [key, arr] = entry;
        arr.sort((a, b) => b.priority - a.priority).splice(Math.min(arr.length, 5));
        return entry;
    });
    return obj;
};

3 Comments

This is a misuse of map. map builds and returns an array. If you're not using map's return value (the array it builds) and don't want to use for-of, use forEach.
I do not agree. Why is this a missue of map? and the question is What is the alternative/best way to map through an object key-values without using forEach?
I said why in my comment above: You're not using the array it creates, so having it create that array is pointless. See MDN: map, forEach. Note that none of the map examples fail to use the array it returns. You're using a screwdriver to hammer a nail. Use a hammer instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.