Сортировать массив объектов на основе другого массива - PullRequest
0 голосов
/ 01 июля 2019

У меня есть массив марок следующим образом:

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 preferred_makes = ['Volkswagen', 'Audi'];

Теперь я делаю следующее:

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)

Но есть ли лучший способ? Могу ли я отсортировать makes, чтобы показать эти preferred_makes как первые элементы массива?

Вот скрипка.

Ответы [ 5 ]

2 голосов
/ 01 июля 2019

Обычный array.sort() с пользовательской функцией сравнения должен быть в состоянии сделать это.

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)
2 голосов
/ 01 июля 2019

Вы можете взять объект с увеличенными на единицу индексами и принять значение по умолчанию Infinity для не найденных имен.Затем сортируйте по разнице значений.

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; }
1 голос
/ 01 июля 2019

Вы можете использовать reduce для создания двух массивов без необходимости сортировки:

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; }

Чтобы сделать это еще быстрее, вы могли бы Set.prototype.has вместо 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; }
0 голосов
/ 02 июля 2019

С помощью lodash вы можете сгенерировать словарь оригинала index по марке автомобиля (indexByMake), используя _.invert(), чтобы получить объект { [car make]: original array index } и отобразить значения обратно в числа.

Используйте _.orderBy() для сортировки массива и используйте значения из indexByMake в соответствии с 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>
0 голосов
/ 01 июля 2019

Вы также можете отсортировать по Array.indexOf, если есть индекс, в противном случае используйте String.localeCompare. На самом деле нет нужды в Лодаше:

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)
...