0

I have a array of makes as follows:

const makes = [
{id: "4", name: "Audi"},
{id: "5", name: "Bmw"},
{id: "6", name: "Porsche"},
{id: "31", name: "Seat"},
{id: "32", name: "Skoda"},
{id: "36", name: "Toyota"},
{id: "38", name: "Volkswagen"}
]

And I want to sort that array based on another array:

const preferred_makes = ['Volkswagen', 'Audi'];

What I do now is as follows:

const preferred_makes = ['Volkswagen', 'Audi'];

const makes = [
{id: "4", name: "Audi"},
{id: "5", name: "Bmw"},
{id: "6", name: "Porsche"},
{id: "31", name: "Seat"},
{id: "32", name: "Skoda"},
{id: "36", name: "Toyota"},
{id: "38", name: "Volkswagen"}
]

const mainMakes = []
const otherMakes = []

makes.map(make => _.includes(preferred_makes, make.name) ? mainMakes.push(make) : otherMakes.push(make))

console.log(mainMakes)
console.log(otherMakes)

But is there any better way? Can I sort makes to show those preferred_makes as first elements of the array?

Here is the fiddle.

5
  • 1
    please add the wanted result. Commented Jul 1, 2019 at 12:56
  • Your approach is bad from every point of view, did you know what's the purpose of function Array.prototype.map? Commented Jul 1, 2019 at 12:57
  • You don't need lodash. ['x'].includes('x') === true Commented Jul 1, 2019 at 12:57
  • @AluanHaddad you don't need to compare a boolean result against a boolean value. You can either negate it or simply use the result. Commented Jul 1, 2019 at 13:02
  • @Ele I was just illustrating that it returns a boolean result in what I thought was a concise way. Commented Jul 1, 2019 at 13:23

5 Answers 5

2

A regular array.sort() with a custom comparison function should be able to do this.

const preferred_makes = ['Volkswagen', 'Audi'];

const makes = [
  {id: "4", name: "Audi"},
  {id: "5", name: "Bmw"},
  {id: "6", name: "Porsche"},
  {id: "31", name: "Seat"},
  {id: "32", name: "Skoda"},
  {id: "36", name: "Toyota"},
  {id: "38", name: "Volkswagen"}
]

const sorted = makes.slice().sort((a, b) => {
  // Convert true and false to 1 and 0
  const aPreferred = new Number(preferred_makes.includes(a.name))
  const bPreferred = new Number(preferred_makes.includes(b.name))
  
  // Return 1, 0, or -1
  return bPreferred - aPreferred
})

console.log(sorted)

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

Comments

2

You could take an object with the by one incremented indices and take a default value of Infinity for not found names. Then sort by the delta of the values.

var preferred_makes = ['Volkswagen', 'Audi'],
    preferred = preferred_makes.reduce((o, k, i) => (o[k] = i + 1, o), {});
    array = [{ id: "4", name: "Audi" }, { id: "5", name: "Bmw" }, { id: "6", name: "Porsche" }, { id: "31", name: "Seat" }, { id: "32", name: "Skoda" }, { id: "36", name: "Toyota" }, { id: "38", name: "Volkswagen" }];

array.sort((a, b) => (preferred[a.name] || Infinity) - (preferred[b.name] || Infinity));

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

Comments

1

You could use reduce to make two arrays without the requirement for sorting:

const preferred_makes = ['Volkswagen','Audi'];
const makes = [{id:"4",name:"Audi"},{id:"5",name:"Bmw"},{id:"6",name:"Porsche"},{id:"31",name:"Seat"},{id:"32",name:"Skoda"},{id:"36",name:"Toyota"},{id:"38",name:"Volkswagen"}];

const [mainMakes, otherMakes] = makes.reduce(([a, b], { id, name }) => ((preferred_makes.includes(name) ? a : b).push({ id, name }), [a, b]), [[], []]);

console.log(mainMakes);
console.log(otherMakes);
.as-console-wrapper { max-height: 100% !important; top: auto; }

To make it even faster, you could Set.prototype.has instead of includes:

const preferred_makes = new Set(['Volkswagen','Audi']);
const makes = [{id:"4",name:"Audi"},{id:"5",name:"Bmw"},{id:"6",name:"Porsche"},{id:"31",name:"Seat"},{id:"32",name:"Skoda"},{id:"36",name:"Toyota"},{id:"38",name:"Volkswagen"}];

const [mainMakes, otherMakes] = makes.reduce(([a, b], { id, name }) => ((preferred_makes.has(name) ? a : b).push({ id, name }), [a, b]), [[], []]);

console.log(mainMakes);
console.log(otherMakes);
.as-console-wrapper { max-height: 100% !important; top: auto; }

Comments

0

With lodash you can generate a dictionary of the original index by the car's make (indexByMake) using _.invert() to get an object of { [car make]: original array index }, and map the values back to numbers.

Use _.orderBy() to sort the array, and use the values from indexByMake according to the name:

const preferred_makes = ['Volkswagen', 'Audi'];
const array = [{ id: "4", name: "Audi" }, { id: "5", name: "Bmw" }, { id: "6", name: "Porsche" }, { id: "31", name: "Seat" }, { id: "32", name: "Skoda" }, { id: "36", name: "Toyota" }, { id: "38", name: "Volkswagen" }];

const indexByMake = _.mapValues(_.invert(preferred_makes), Number);

const result = _.sortBy(array, ({ name }) => indexByMake[name]);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Comments

0

You can also sort by the Array.indexOf if the index is there otherwise use String.localeCompare. No real need for lodash really:

const makes = [ {id: "4", name: "Audi"}, {id: "6", name: "Porsche"}, {id: "31", name: "Seat"}, {id: "32", name: "Skoda"}, {id: "5", name: "Bmw"}, {id: "36", name: "Toyota"}, {id: "38", name: "Volkswagen"} ] 
const list = ['Volkswagen', 'Audi'];

let result = makes.sort((a,b) => {
  let i = list.indexOf(a.name)
  return i < 0 ? a.name.localeCompare(b.name) : list.indexOf(b.name) - i
})

console.log(result)

Comments

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.