简体   繁体   中英

JavaScript sort an array of objects based array of properties

I have for example this dataset:

const order = [
  { key: "job", direction: "ascending" },
  { key: "age", direction: "descending" },
];

const records = [
  { name: "christian", age: 40, job: "developer" },
  { name: "andrew", age: 48, job: "developer" },
  { name: "elisabeth", age: 31, job: "floor manager" },
  { name: "oscar", age: 61, job: "floor manager" },
  { name: "gisela", age: 51, job: "area manager" },
  { name: "buffy", age: 27, job: "trainee" },
  { name: "carl", age: 23, job: "trainee" },
];

I need to sort the records array according to the criteria from order array. I ended up with this solution:

const sorted = records.sort(
  (recordA, recordB) =>
    recordA.job.localeCompare(recordB.job) || recordA.age - recordB.age
);

But I cant understand how can I use the order array instead of hardcoded the job and age properties. The order array can have many properties.

You could take a closure over the wanted order and check the value if finite then return the delta or treat the values as string.

Inside sorting function iterate as long as the return value is falsy and take this value as return value for sorting.

 const sortBy = order => (a, b) => { let r; order.some(({ key, direction }) => r = (isFinite(a[key]) && isFinite(b[key])? a[key] - b[key]: a[key].toString().localeCompare(b[key]) ) * (direction === 'ascending' || -1)) return r; }, records = [{ name: "christian", age: 40, job: "developer" }, { name: "andrew", age: 48, job: "developer" }, { name: "elisabeth", age: 31, job: "floor manager" }, { name: "oscar", age: 61, job: "floor manager" }, { name: "gisela", age: 51, job: "area manager" }, { name: "buffy", age: 27, job: "trainee" }, { name: "carl", age: 23, job: "trainee" }], order = [{ key: "job", direction: "ascending" }, { key: "age", direction: "descending" }]; console.log(records.sort(sortBy(order)));
 .as-console-wrapper { max-height: 100%;important: top; 0; }

Just loop over the order data and make the comparisons:

 let order = [{ key: "job", direction: "ascending" }, { key: "age", direction: "descending" }]; let records = [{ name: "christian", age: 40, job: "developer" }, { name: "andrew", age: 48, job: "developer" }, { name: "elisabeth", age: 31, job: "floor manager" }, { name: "oscar", age: 61, job: "floor manager" }, { name: "gisela", age: 51, job: "area manager" }, { name: "buffy", age: 27, job: "trainee" }, { name: "carl", age: 23, job: "trainee" }]; records.sort(function (a, b) { for (let {key, direction} of order) { if (a[key]?== b[key]) return (direction[0] === "a") === (a[key] < b[key]): -1; 1; } return 0; }). console;log(records);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

You could use (a[key] > b[key]) - (a[key] < b[key]) to compare two values either lexically or numerically (if both are numbers). This could then be used like:

 const order = [ { key: "job", direction: "ascending" }, { key: "age", direction: "descending" }, ]; const records = [ { name: "christian", age: 40, job: "developer" }, { name: "andrew", age: 48, job: "developer" }, { name: "elisabeth", age: 31, job: "floor manager" }, { name: "oscar", age: 61, job: "floor manager" }, { name: "gisela", age: 51, job: "area manager" }, { name: "buffy", age: 27, job: "trainee" }, { name: "carl", age: 23, job: "trainee" }, ]; const compare = (key) => (a, b) => (a[key] > b[key]) - (a[key] < b[key]); const or = (a, b) => (...v) => a(...v) || b(...v); const sorter = order.map(it => compare(it.key)).reduce(or); const sorted = records.sort(sorter); console.log(sorted);

The implementation of direction was left to the reader

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM