简体   繁体   中英

Sorting array containing objects using complex/dynamic criteria (ascending and descending)?

We have an array with data and I want to sort it by users key:

  • If users have 1 object, I sort by its name property.

  • If users have more than 1 entry, I sort by users.length .

Example:

DESCENDING: Zorya, Gorya, Dorya, Borya, Aorya, 4, 2, 0

 ASCENDING: Aorya, Borya, Dorya, Gorya, Zorya, 2, 4, 0

This is what I've done so far:

 const array = [{ name: "qw", users: [ { name: "Borya" }, ], }, { name: "qw", users: [ { name: "Gorya" }, ], }, { name: "qw", users: [ { name: "Zorya" }, ] }, { name: "qw", users: [ { name: "Var" }, { name: "Var2" }, ], }, { name: "qw", users: [], }, { name: "qw", users: [ { name: "Aorya" }, ], }, { name: "qw", users: [ { name: "rwerwerwe" }, { name: "tregdf" }, { name: "gdfgdf" }, { name: "Vayetrtertrr2" }, ] }, { name: "qw", users: [ { name: "Dorya" }, ], }]; function orderCustomBy(collection, key, direction) { const direct = direction === "desc"? -1: 1; let compare = (a, b) => { if (a === null) return -1; if (b === null) return 1; // Just commenting this out because there's no `intlCollator` in here: // return intlCollator.compare(a, b); }; if (key === "users") { compare = (a, b) => { // What should go in here? // intlCollator.compare(a[0].name, b[0].name); return 1; }; } return [].concat(collection).sort((a, b) => { const result = compare(a[key], b[key]); return result * direct; }); } console.log(orderCustomBy(array, 'users', 'asc').map(item => item.users.length === 1? item.users[0].name: item.users.length)); console.log(orderCustomBy(array, 'users', 'desc').map(item => item.users.length === 1? item.users[0].name: item.users.length));
 .as-console-wrapper { max-height: 100%;important; }

You basically need to account for a few different combinations inside the compare function when key === 'users :

  • Both have a single user, so we compare user[0].name .

  • Only a has a single user, so a goes before b .

  • Only b has a single user, so b goes before a .

  • None have a single user, so we just compare users.length .

It will look something like this:

if (a.users.length === 1 && b.users.length === 1) {
  // If both have a single user, sort by users[0].name:
  return a.users[0].name.localeCompare(b.users[0].name);
} else if (a.users.length === 1) {
  // If only `a` has a single user, `a` goes before `b`:
  return -1;
} else if (b.users.length === 1) {
  // If only `b` has a single user, `b` goes before `a`:
  return 1;
}

// Otherwise, sort by users.length:
return a.users.length - b.users.length;

Here you can see it in action:

 const array = [{ name: "qw", users: [ { name: "Borya" }, ], }, { name: "qw", users: [ { name: "Gorya" }, ], }, { name: "qw", users: [ { name: "Zorya" }, ] }, { name: "qw", users: [ { name: "Var" }, { name: "Var2" }, ], }, { name: "qw", users: [], }, { name: "qw", users: [ { name: "Aorya" }, ], }, { name: "qw", users: [ { name: "rwerwerwe" }, { name: "tregdf" }, { name: "gdfgdf" }, { name: "Vayetrtertrr2" }, ] }, { name: "qw", users: [ { name: "Dorya" }, ], }]; function orderCustomBy(collection, key, direction) { const direct = direction === "desc"? -1: 1; let compare; if (key === "users") { compare = (a, b) => { if (a.users.length === 1 && b.users.length === 1) { // If both have a single user, sort by users[0].name: return a.users[0].name.localeCompare(b.users[0].name); } else if (a.users.length === 1) { // If only `a` has a single user, `a` goes before `b`: return -1; } else if (b.users.length === 1) { // If only `b` has a single user, `b` goes before `a`: return 1; } // Otherwise, sort by users.length: return a.users.length - b.users.length; }; } else { compare = (a, b) => { if (a === null) return -1; if (b === null) return 1; // Just commenting this out because there's no `intlCollator` in here: // return intlCollator.compare(a, b); }; } return [].concat(collection).sort((a, b) => compare(a, b) * direct); } console.log(orderCustomBy(array, 'users', 'asc').map(item => item.users.length === 1? item.users[0].name: item.users.length)); console.log(orderCustomBy(array, 'users', 'desc').map(item => item.users.length === 1? item.users[0].name: item.users.length));
 .as-console-wrapper { max-height: 100%;important; }

Since these criteria for sorting are complicated, it's a good idea to first transform the complex array into a simpler one that's easier to reason about and sort.

The simplifyArray() function below does that, producing this unsorted array:

[ "Borya", "Gorya", "Zorya", "2", "0", "Aorya", "4", "Dorya" ]

Sorting it ought to be straightforward.

 function simplifyArray (arr) { return arr.map(el => { let length = el.users.length; if (length === 1) { return el.users[0].name; } else return String(length); }); } const array = [ { name: "qw", users: [ { name: "Borya" } ] }, { name: "qw", users: [ { name: "Gorya" } ] }, { name: "qw", users: [ { name: "Zorya" } ] }, { name: "qw", users: [ { name: "Var" }, { name: "Var2" } ] }, { name: "qw", users: [] }, { name: "qw", users: [ { name: "Aorya" } ] }, { name: "qw", users: [ { name: "rwerwerwe" }, { name: "tregdf" }, { name: "gdfgdf" }, { name: "Vayetrtertrr2" } ] }, { name: "qw", users: [ { name: "Dorya" } ] }, ]; const simplerArray = simplifyArray(array); console.log(simplerArray);

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