Reputation: 443
I have an array of objects that I need sorted. If the object has class "search-filter-type", it needs to be sorted by specific order (see: car_types_order). For all other objects in the array, it should be sorted alphabetically by label. What I have below works, I'm wondering if there should be two separate sort functions or if there is a cleaner way of achieving this? Thanks!
Code:
var car_types_order = ['Small Cars', 'Medium Cars', 'Large Cars', 'SUVs & Crossovers', 'Vans', 'Luxury',
'Convertibles', 'Sports', 'Wagons', 'Hybrids', 'Electric', 'Pickup Trucks', 'Off-Road Vehicles', 'RVs',
'Commercial', 'Specialty'];
filters.sort(function(a, b){
if (a.class == "search-filter-type" || b.class == "search-filter-type")
return car_types_order.indexOf(a.label) - car_types_order.indexOf(b.label);
else
{
if (a.label < b.label)
return -1;
if (a.label > b.label)
return 1;
}
return 0;
});
Example Objects:
{title: "Rental Company", class: "search-filter-company", label: "Hertz", id: "filter-companies-HZ", value: "HZ"}
{title: "Rental Company", class: "search-filter-company", label: "Silvercar", id: "filter-companies-SC", value: "SC"}
{title: "Rental Company", class: "search-filter-company", label: "NextCar", id: "filter-companies-NC", value: "NC"}
{title: "Rental Company", class: "search-filter-company", label: "National", id: "filter-companies-NA", value: "NA"}
{title: "Rental Company", class: "search-filter-company", label: "Payless", id: "filter-companies-ZA", value: "ZA"}
{title: "Rental Company", class: "search-filter-company", label: "Sixt", id: "filter-companies-SX", value: "SX"}
{title: "Rental Company", class: "search-filter-company", label: "Thrifty", id: "filter-companies-ZT", value: "ZT"}
{title: "Car Type", class: "search-filter-type", label: "Commercial", id: "filter-types-commercial", value: "SKAR"}
{title: "Rental Company", class: "search-filter-company", label: "Routes", id: "filter-companies-RO", value: "RO"}
{title: "Car Type", class: "search-filter-type", label: "Electric", id: "filter-types-electric", value: "ICAE"}
{title: "Car Type", class: "search-filter-type", label: "Medium Cars", id: "filter-types-medium", value: "FCAR"}
{title: "Car Type", class: "search-filter-type", label: "Small Cars", id: "filter-types-small", value: "CCAR"}
Upvotes: 2
Views: 116
Reputation:
Don't be allured by "clever" hacks that provide short code that becomes very difficult to interpret, and therefore likely to obscure nasty bugs.
Write clear, descriptive code so that others (and even yourself at a later date) can quickly comprehend its intent. Here's an example:
var data = [{ title: "Rental Company", class: "search-filter-company", label: "Hertz", id: "filter-companies-HZ", value: "HZ" }, { title: "Rental Company", class: "search-filter-company", label: "National", id: "filter-companies-NA", value: "NA" }, { title: "Rental Company", class: "search-filter-company", label: "NextCar", id: "filter-companies-NC", value: "NC" }, { title: "Rental Company", class: "search-filter-company", label: "Payless", id: "filter-companies-ZA", value: "ZA" }, { title: "Rental Company", class: "search-filter-company", label: "Silvercar", id: "filter-companies-SC", value: "SC" }, { title: "Rental Company", class: "search-filter-company", label: "Sixt", id: "filter-companies-SX", value: "SX" }, { title: "Rental Company", class: "search-filter-company", label: "Thrifty", id: "filter-companies-ZT", value: "ZT" }, { title: "Car Type", class: "search-filter-type", label: "Commercial", id: "filter-types-commercial", value: "SKAR" }, { title: "Rental Company", class: "search-filter-company", label: "Routes", id: "filter-companies-RO", value: "RO" }, { title: "Car Type", class: "search-filter-type", label: "Electric", id: "filter-types-electric", value: "ICAE" }, { title: "Car Type", class: "search-filter-type", label: "Medium Cars", id: "filter-types-medium", value: "FCAR" }, { title: "Car Type", class: "search-filter-type", label: "Small Cars", id: "filter-types-small", value: "CCAR" }],
car_types_order = ['Small Cars', 'Medium Cars', 'Large Cars', 'SUVs & Crossovers', 'Vans', 'Luxury', 'Convertibles', 'Sports', 'Wagons', 'Hybrids', 'Electric', 'Pickup Trucks', 'Off-Road Vehicles', 'RVs', 'Commercial', 'Specialty'];
data.sort((a, b) => {
const aSearchArray = a.class === "search-filter-type";
const bSearchArray = b.class === "search-filter-type";
if (aSearchArray !== bSearchArray) { // Group by ordering method
return aSearchArray ? 1 : -1;
}
if (aSearchArray) { // They both need to search the array
return car_types_order.indexOf(a.label) - car_types_order.indexOf(b.label);
}
return a.label.localeCompare(b.label); // Order them lexically
});
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is guaranteed to never search the array unless both objects have the "search-filter-type"
class. Nor will it perform a lexical comparison of .label
if neither have that class.
As a potential performance enhancement, use a Map
of strings to order number instead of an Array
for the car_types_order
.
This demo starts with an Array
but uses it only to build the Map
.
var data = [{ title: "Rental Company", class: "search-filter-company", label: "Hertz", id: "filter-companies-HZ", value: "HZ" }, { title: "Rental Company", class: "search-filter-company", label: "National", id: "filter-companies-NA", value: "NA" }, { title: "Rental Company", class: "search-filter-company", label: "NextCar", id: "filter-companies-NC", value: "NC" }, { title: "Rental Company", class: "search-filter-company", label: "Payless", id: "filter-companies-ZA", value: "ZA" }, { title: "Rental Company", class: "search-filter-company", label: "Silvercar", id: "filter-companies-SC", value: "SC" }, { title: "Rental Company", class: "search-filter-company", label: "Sixt", id: "filter-companies-SX", value: "SX" }, { title: "Rental Company", class: "search-filter-company", label: "Thrifty", id: "filter-companies-ZT", value: "ZT" }, { title: "Car Type", class: "search-filter-type", label: "Commercial", id: "filter-types-commercial", value: "SKAR" }, { title: "Rental Company", class: "search-filter-company", label: "Routes", id: "filter-companies-RO", value: "RO" }, { title: "Car Type", class: "search-filter-type", label: "Electric", id: "filter-types-electric", value: "ICAE" }, { title: "Car Type", class: "search-filter-type", label: "Medium Cars", id: "filter-types-medium", value: "FCAR" }, { title: "Car Type", class: "search-filter-type", label: "Small Cars", id: "filter-types-small", value: "CCAR" }],
car_types_order = new Map(['Small Cars', 'Medium Cars', 'Large Cars', 'SUVs & Crossovers', 'Vans', 'Luxury', 'Convertibles', 'Sports', 'Wagons', 'Hybrids', 'Electric', 'Pickup Trucks', 'Off-Road Vehicles', 'RVs', 'Commercial', 'Specialty'].map((s, i) => [s, i+1]));
data.sort((a, b) => {
const aSearchMap = a.class === "search-filter-type";
const bSearchMap = b.class === "search-filter-type";
if (aSearchMap !== bSearchMap) { // Group by ordering method
return aSearchMap ? 1 : -1;
}
if (aSearchMap) { // They both need to search the map
return (car_types_order.get(a.label) || 0) - (car_types_order.get(b.label) || 0);
}
return a.label.localeCompare(b.label); // Order them lexically
});
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 386604
You could first check if 'search-filter-type'
is given and sort this items to botton, if both given, the sort by index and if same, then sort by alphabet.
For sorting 'search-filter-type'
to top, you could swap a
and b
in this line:
(a.class === "search-filter-type") - (b.class === "search-filter-type")
var data = [{ title: "Rental Company", class: "search-filter-company", label: "Hertz", id: "filter-companies-HZ", value: "HZ" }, { title: "Rental Company", class: "search-filter-company", label: "National", id: "filter-companies-NA", value: "NA" }, { title: "Rental Company", class: "search-filter-company", label: "NextCar", id: "filter-companies-NC", value: "NC" }, { title: "Rental Company", class: "search-filter-company", label: "Payless", id: "filter-companies-ZA", value: "ZA" }, { title: "Rental Company", class: "search-filter-company", label: "Silvercar", id: "filter-companies-SC", value: "SC" }, { title: "Rental Company", class: "search-filter-company", label: "Sixt", id: "filter-companies-SX", value: "SX" }, { title: "Rental Company", class: "search-filter-company", label: "Thrifty", id: "filter-companies-ZT", value: "ZT" }, { title: "Car Type", class: "search-filter-type", label: "Commercial", id: "filter-types-commercial", value: "SKAR" }, { title: "Rental Company", class: "search-filter-company", label: "Routes", id: "filter-companies-RO", value: "RO" }, { title: "Car Type", class: "search-filter-type", label: "Electric", id: "filter-types-electric", value: "ICAE" }, { title: "Car Type", class: "search-filter-type", label: "Medium Cars", id: "filter-types-medium", value: "FCAR" }, { title: "Car Type", class: "search-filter-type", label: "Small Cars", id: "filter-types-small", value: "CCAR" }],
car_types_order = ['Small Cars', 'Medium Cars', 'Large Cars', 'SUVs & Crossovers', 'Vans', 'Luxury', 'Convertibles', 'Sports', 'Wagons', 'Hybrids', 'Electric', 'Pickup Trucks', 'Off-Road Vehicles', 'RVs', 'Commercial', 'Specialty'];
data.sort((a, b) =>
(a.class === "search-filter-type") - (b.class === "search-filter-type")
|| car_types_order.indexOf(a.label) - car_types_order.indexOf(b.label)
|| a.label.localeCompare(b.label)
);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Some more advanced techniques:
Use an object for accessing the order of car types.
Take a default value for not found types. This requires not to use a falsy value, like zero, for known types.
var data = [{ title: "Rental Company", class: "search-filter-company", label: "Hertz", id: "filter-companies-HZ", value: "HZ" }, { title: "Rental Company", class: "search-filter-company", label: "National", id: "filter-companies-NA", value: "NA" }, { title: "Rental Company", class: "search-filter-company", label: "NextCar", id: "filter-companies-NC", value: "NC" }, { title: "Rental Company", class: "search-filter-company", label: "Payless", id: "filter-companies-ZA", value: "ZA" }, { title: "Rental Company", class: "search-filter-company", label: "Silvercar", id: "filter-companies-SC", value: "SC" }, { title: "Rental Company", class: "search-filter-company", label: "Sixt", id: "filter-companies-SX", value: "SX" }, { title: "Rental Company", class: "search-filter-company", label: "Thrifty", id: "filter-companies-ZT", value: "ZT" }, { title: "Car Type", class: "search-filter-type", label: "Commercial", id: "filter-types-commercial", value: "SKAR" }, { title: "Rental Company", class: "search-filter-company", label: "Routes", id: "filter-companies-RO", value: "RO" }, { title: "Car Type", class: "search-filter-type", label: "Electric", id: "filter-types-electric", value: "ICAE" }, { title: "Car Type", class: "search-filter-type", label: "Medium Cars", id: "filter-types-medium", value: "FCAR" }, { title: "Car Type", class: "search-filter-type", label: "Small Cars", id: "filter-types-small", value: "CCAR" }],
car_types_order = ['Small Cars', 'Medium Cars', 'Large Cars', 'SUVs & Crossovers', 'Vans', 'Luxury', 'Convertibles', 'Sports', 'Wagons', 'Hybrids', 'Electric', 'Pickup Trucks', 'Off-Road Vehicles', 'RVs', 'Commercial', 'Specialty'],
order = Object.assign({ default: 0 }, ...car_types_order.map((k, v) => ({ [k]: v + 1 })));
data.sort((a, b) =>
(a.class === "search-filter-type") - (b.class === "search-filter-type")
|| (order[a.label] || order.default) - (order[b.label] || order.default)
|| a.label.localeCompare(b.label)
);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1