0

In JavaScript, I have an array of objects and an input value like this:

const inputVal = 'foo';

const objArray = [
    {title: 'blahaa', type: 'foobar'},
    {title: 'foobar', type: 'wohoo'},
    {title: 'foobar', type: 'foobar'},
    {title: 'foobar', type: 'aaaabaa'},
    {title: 'foobar', type: 'moo'},
    {title: 'aaah', type: 'foogoo'},
    {title: 'foohiii', type: 'foobar'},
    {title: 'aaah', type: 'foobar'},
    {title: 'foodoo', type: 'aaaabaa'},
    {title: 'gaaaaaah', type: 'foobar'},
    {title: 'foobar', type: 'foogoo'},
];

As you can see, all elements in the array have properties starting with "foo" in either the title or the type. Also, all elements are unique, the same title and/or type can be in several elements, but the same combination of both cannot appear twice.

I want to sort this array in the following way:

  1. Both title and type starts with inputVal
    1. Type alphabetically
    2. Title alphabetically
  2. Title starts with inputVal but not type
    1. Type alphabetically
    2. Title alphabetically
  3. Type starts with inputVal but not title
    1. Type alphabetically
    2. Title alphabetically

The example list would be sorted as following:

const objArray = [
    {title: 'foobar', type: 'foobar'}, // Criterium 1
    {title: 'foohiii', type: 'foobar'}, // Criterium 1
    {title: 'foobar', type: 'foogoo'}, // Criterium 1
    {title: 'foobar', type: 'aaaabaa'}, // Criterium 2
    {title: 'foodoo', type: 'aaaabaa'}, // Criterium 2
    {title: 'foobar', type: 'moo'}, // Criterium 2
    {title: 'foobar', type: 'wohoo'}, // Criterium 2
    {title: 'aaah', type: 'foobar'}, // Criterium 3
    {title: 'blahaa', type: 'foobar'}, // Criterium 3
    {title: 'gaaaaaah', type: 'foobar'}, // Criterium 3
    {title: 'aaah', type: 'foogoo'}, // Criterium 3
];

I tried using array.prototype.sort(callback) with several different callback functions, but I don't seem to get the correct one. Can anyone help me?

5
  • What should happen if foo isn’t included anywhere? Commented Aug 14, 2019 at 11:33
  • 1
    please display your existing callback function Commented Aug 14, 2019 at 11:34
  • What are the different callback that you've checked? Commented Aug 14, 2019 at 11:34
  • Please add your attempt to the question. Have you tried using startsWith? Commented Aug 14, 2019 at 11:36
  • why is aaah below gaaaaah? in the original order both have a different order and no rule switches them. Commented Aug 14, 2019 at 11:58

3 Answers 3

3

You could chanin the criteria and sort by the three groups first and then by the values.

const
    value = 'foo',
    start = (v => s => s.startsWith(v))(value),
    array = [{ title: 'blahaa', type: 'foobar' }, { title: 'foobar', type: 'wohoo' }, { title: 'foobar', type: 'foobar' }, { title: 'foobar', type: 'aaaabaa' }, { title: 'foobar', type: 'moo' }, { title: 'aaah', type: 'foogoo' }, { title: 'foohiii', type: 'foobar' }, { title: 'aaah', type: 'foobar' }, { title: 'foodoo', type: 'aaaabaa' }, { title: 'gaaaaaah', type: 'foobar' }, { title: 'foobar', type: 'foogoo' }];
    
array.sort((a, b) =>
       (start(b.title) && start(b.type)) - (start(a.title) && start(a.title))
    || start(b.title) - start(a.title)
    || start(b.type) - start(a.type)
    || a.type.localeCompare(b.type)
    || a.title.localeCompare(b.title)
);

console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

Comments

0

Here is another solution, probably less efficient due to the use of multiple regex.

const objArray = [
    {title: 'blahaa', type: 'foobar'},
    {title: 'foobar', type: 'wohoo'},
    {title: 'foobar', type: 'foobar'},
    {title: 'foobar', type: 'aaaabaa'},
    {title: 'foobar', type: 'moo'},
    {title: 'aaah', type: 'foogoo'},
    {title: 'foohiii', type: 'foobar'},
    {title: 'aaah', type: 'foobar'},
    {title: 'foodoo', type: 'aaaabaa'},
    {title: 'gaaaaaah', type: 'foobar'},
    {title: 'foobar', type: 'foogoo'}
];

const input = "foo";

const sortedObjArray = [
    objArray.sort((a, b) => {
        const
            regex = new RegExp("^(" + input + ")?(.*)", "i"),
            titleAExec = regex.exec(a.title),
            typeAExec = regex.exec(a.type),
            titleBExec = regex.exec(b.title),
            typeBExec = regex.exec(b.type)

        const
            titleComparison = titleAExec[2].localeCompare(titleBExec[2]),
            typeComparison = typeAExec[2].localeCompare(typeBExec[2])

        if (titleAExec[1] && !titleBExec[1])
            return -1
        else if (titleBExec[1] && !titleAExec[1])
            return 1

        if (typeAExec[1] && !typeBExec[1])
            return -1
        else if (typeBExec[1] && !typeAExec[1])
            return 1

        if (typeComparison === 0)
            return titleComparison

        return typeComparison;
    })
]

console.log(sortedObjArray)

Comments

-1

You can try the following:

  1. Split array in 3 subarrays using Array.prototype.filter based on 3 Criterias as mentioned above.
  2. Sort 3 subarrays independently and then concatenate using Array.prototype.concat

To improve performance, process all subarrays asynchronously. Divide and Conquer wins!

7 Comments

Filter wouldn't work here filter removes elements, rather, sort would. You've generalised the problem and haven't provided a clear solution. Asynchronicity is unrelated to this problem. Try creating a runnable solution instead, that actually works, and backup why it would work, rather than just stating it.
By split I meant doing this -> jsfiddle.net/y1wL7dsq and now each array can be alphabetically sorted in async before doing concat.
Why don't you make a snippet here then, showing what you mean?
It worked, but you can place that code into a snippet here.
I still don't understand why my answer is downvoted. I assumed OP is already familiar with sorting alphabetically and only provided the main logic that was required.
|

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.