Сортировать по объекту внутри объекта в JavaScript - PullRequest
3 голосов
/ 17 января 2020

У меня есть список persons, и я сортирую его по столбцу в sortColumn.

const persons = [{
    name: "alireza",
    family: "seif",
    other: {
      age: 28,
      rate: 30
    }
  },
  {
    name: "sara",
    family: "niki",
    other: {
      age: 15,
      rate: 15
    }
  },
  {
    name: "fateme",
    family: "azizy",
    other: {
      age: 27,
      rate: 35
    }
  }
];
const sortColumn = {
  path: "name",
  order: "asc"
};
persons.sort((person1, person2) =>
  person1[sortColumn.path] > person2[sortColumn.path] ?
  sortColumn.order === "asc" ?
  1 :
  -1 :
  person2[sortColumn.path] > person1[sortColumn.path] ?
  sortColumn.order === "asc" ?
  -1 :
  1 :
  0
);
console.log(persons);

Если sortColumn.path равно "name" и order равно "asc" (или "desc"), функция sort работает правильно. Но как мне сортировать по "other.age"?

Спасибо.

Ответы [ 3 ]

3 голосов
/ 17 января 2020

Вы можете использовать функцию, которая возвращает функцию сортировки, в зависимости от порядка сортировки.

Эта функция сортировки использует другую функцию для получения значения из объекта путем уменьшения разделенного пути до значения.

const
    sortBy = ({ order = 'asc', path }) => order === 'asc'
        ? (a, b) => ((a, b) => a > b || -(a < b))(getValue(a, path), getValue(b, path))
        : (a, b) => ((a, b) => b > a || -(b < a))(getValue(a, path), getValue(b, path)),
    getValue = (object, keys) => keys.split('.').reduce((o, k) => o[k], object),
    persons = [{ name: "sara", family: "niki", other: { age: 15, rate: 15 } }, { name: "alireza", family: "seif", other: { age: 28, rate: 30 } }, { name: "fateme", family: "azizy", other: { age: 27, rate: 35 } }];

console.log(persons.sort(sortBy({ path: "name", order: "asc" })));
console.log(persons.sort(sortBy({ path: "other.rate", order: "desc" })));
.as-console-wrapper { max-height: 100% !important; top: 0; }
1 голос
/ 17 января 2020

Главное, чтобы ваш код ожидал, что path будет функцией, которая выбирает значение свойства вместо строки, указывающей на имя свойства. Таким образом, это намного более гибко.

const sortColumn = {
    path: p => p.other.age,
    order: 'desc'
};

Однако, если «индивидуумы» - не единственный объект, с которым вы хотите это сделать, вы можете дополнительно абстрагировать такую ​​функцию для общего использования с любым массивом, например, таким:

function sorter (array, path, order) {

  array.sort((a,b) => {

    let result = 
      path(a) > path(b) ? 1
      : path(a) < path(b) ? -1
      : 0;

    if (order === "desc")
      result = -result;

    return result;

  });

}

Используйте это так:

sorter(persons, p => p.other.age, 'desc');

Разверните и запустите приведенный ниже фрагмент, чтобы увидеть его в действии:

function sorter (array, path, order) {

  array.sort((a,b) => {

    let result = 
      path(a) > path(b) ? 1
      : path(a) < path(b) ? -1
      : 0;

    if (order === "desc")
      result = -result;

    return result;

  });
  
}

const persons = [
      {name: "alireza", family: "seif", other: {age: 28, rate: 30}},
      {name: "sara", family: "niki", other: {age: 15, rate: 15}},
      {name: "fateme", family: "azizy", other: {age: 27, rate: 35}}
];

// convenience function
let sortAndLog = (array, path, order) => {
    sorter(array, path, order);
    console.log(array.map(path));
}
sortAndLog(persons, p => p.name, "asc");
sortAndLog(persons, p => p.name, "desc");
sortAndLog(persons, p => p.other.age, "asc");
sortAndLog(persons, p => p.other.age, "desc");
1 голос
/ 17 января 2020

Если вы хотите выполнить сортировку по этому глубокому свойству age, вы не можете использовать sortColumn точно так же, как вы используете ... Вместо этого, один из вариантов - изменить его, сделав его массивом свойств, например :

sortColumn = { path:["other","age"], order:"asc" }

Таким образом, вам также придется изменить функцию сортировки - как показано в примере ниже:

const persons = [
  {name:"alireza",family:"seif",other:{age:28,rate:30}},
  {name:"fateme",family:"azizy",other:{age:27,rate:35}},
  {name:"sara",family:"niki",other:{age:15,rate:15}}
]

const sortColumn = { path:["other","age"], order:"asc" }

persons.sort((person1, person2) =>
  person1[sortColumn.path[0]][sortColumn.path[1]] > person2[sortColumn.path[0]][sortColumn.path[1]] 
    ? sortColumn.order === "asc"
      ? 1
      : -1
    : person2[sortColumn.path[0]][sortColumn.path[1]]  > person1[sortColumn.path[0]][sortColumn.path[1]] 
    ? sortColumn.order === "asc"
      ? -1
      : 1
    : 0
);

console.log(persons)

Однако , этот подход не работает для сортировки по "name", так как эта функция сортировки сортирует ваши данные по некоторому фрагменту данных, который равен двум -слой глубокий (внутри "other", затем "age"). Вот модификация, которую вы можете внести в функцию сортировки, которая позволяет вам сортировать по любым свойствам, любому количеству слоев в ваших данных:

const persons = [
  {name:"alireza",family:"seif",other:{age:28,rate:30}},
  {name:"fateme",family:"azizy",other:{age:27,rate:35}},
  {name:"sara",family:"niki",other:{age:15,rate:15}}
]

const sortColumn = { path:["name"], order:"asc" }

persons.sort((person1, person2) => {
  // get array of paths
  const sortPaths = sortColumn.path;

  // get values to sort by
  const val1 = sortPaths.reduce((acc, path) => {
    if (acc[path]) return acc[path]
    else alert(`can't find prop ${path} in person1`);
  }, person1)
  const val2 = sortPaths.reduce((acc, path) => {
    if (acc[path]) return acc[path]
    else alert(`can't find prop ${path} in person2`);
  }, person2)

  return val1 > val2 
    ? sortColumn.order === "asc"
      ? 1
      : -1
    : val2  > val1 
    ? sortColumn.order === "asc"
      ? -1
      : 1
    : 0
});

console.log(persons)

Как вы можете видеть из этого второго фрагмента, теперь вы можете искать по мелкому свойству "name", используя path: ["name"], но если вы хотите отсортировать по глубокому значению, просто добавьте оба свойства в массив path следующим образом: path: ["other", "age"]

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...