2
\$\begingroup\$

I'm trying to create a sorted array based on the below input data:

Input:

[{"title": "100_baz"}, {"title": "01_foo"}, {"title": "05_bar"}]

function indexSort (input) {    
    let output = [];
    input.forEach(value => {    
        if (value.title && value.title.indexOf('_') !== -1) {
            let targetIndex = parseInt (value.title.split('_')[0]);
            let title = value.title.substring(value.title.indexOf('_') + 1, value.title.length); // extract the string next to '_'
            output[targetIndex] = title;
        }    
    })
    console.log(output)
}

Desired Output:

enter image description here

I'm able to get the desired output using the above code snippet, however, I'm looking for a better way to achieve this in terms of good practice, or a concise and clear method in ES5 or ES6.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ There is a slight issue with your desired output. It looks like you want a dictionary because you have key value pairs, but you have it surrounded with brackets like an array. Can you clarify the structure of your desired output? Are you looking for an array or a dictionary? \$\endgroup\$
    – Olyve
    Commented Feb 17, 2020 at 19:29
  • \$\begingroup\$ @SamG Strictly looking for an array in order to retain the order/index. I have updated the desired output now. \$\endgroup\$ Commented Feb 18, 2020 at 12:59

2 Answers 2

3
\$\begingroup\$

Updating my comments on current implementation, Thanks @Mast for pointing out.

  1. You have used let for output, targetIndex and title. None of them never updated. const is better suitable here.
  2. Usage of value.title.indexOf('_') is repeated. you can use variable.
  3. You can avoid substring usage because you are already did value.title.split('_') and you can use index 1 value from result array.

Apart from these minor points, code looks good to me.

As you asked, Here is alternative ES6 implementation.

  1. Use arrow function
  2. With reduce and using destructure in input function arguments and have the default value for title.
  3. In reduce function use destucture to get the values from split result.

const data = [{"title": "100_baz"}, {"title": "01_foo"}, {"title": "05_bar"}];

const indexSort = data => data.reduce((acc, {title = ''}) => {
  const [num, value] = title.split('_');
  acc[Number(num)] = value;
  return acc;
}, []);

console.log(indexSort(data));

\$\endgroup\$
3
  • \$\begingroup\$ You have presented an alternative solution, but haven't reviewed the code. Please explain your reasoning (how your solution works and why it is better than the original) so that the author and other readers can learn from your thought process. \$\endgroup\$
    – Mast
    Commented Feb 19, 2020 at 21:14
  • 1
    \$\begingroup\$ @Mast, Thanks for suggestion. I just updated my thoughts. \$\endgroup\$ Commented Feb 20, 2020 at 4:32
  • \$\begingroup\$ It’s a matter of opinion, but I prefer only using const when the intention of the variable is to never change. In this case, it is a coincidence (caused by the chosen implementation) that the variable never got updated, so I would use let instead. \$\endgroup\$ Commented Feb 20, 2020 at 23:25
2
\$\begingroup\$

Your code is pretty sound. I can't see any improvements that specifically use ES5/ES6 tricks - the spread operator for example will set all of the other keys to undefined instead of leaving them empty, which I think is undesired. Further loops would iterate over those undefined keys as well.

That said, here are some improvements:

  • Use reduce to remove the need for a new array and replace the forEach
  • Store the return value from split and use that to replace the indexOf (if the delimiter doesn't exist split returns an array of length 1) and substring calls
  • At the moment, the indexSort function isn't as single-purpose as it could be. It has to know that the input array contains a title key. This can be moved outside to where the function is called making indexSort reusable
  • The name indexSort is a little misleading - I assumed it was going to sort a preexisting array. Perhaps use something like arrayFromTitles instead?

Quick snippet showing these changes:

function indexSort (input) {
    return input.reduce((accumulator, current) => {
        let split = current.split('_');
        if ( split.length > 1 ) {
            accumulator[parseInt(split[0])] = split[1];
        }
        return accumulator;
    }, []);
}

let titles = [{"title": "100_baz"}, {"title": "01_foo"}, {"title": "05_bar"}];
indexSort(titles.map(x => x.title));
\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.