【问题标题】:How to use JS Sort to sort Multiple Elements如何使用 JS Sort 对多个元素进行排序
【发布时间】:2018-05-01 17:58:02
【问题描述】:

我有一个需要排序的对象数组。如果对象具有“search-filter-type”类,则需要按特定顺序排序(参见:car_types_order)。对于数组中的所有其他对象,它应该按标签的字母顺序排序。我下面的作品,我想知道是否应该有两个单独的排序功能,或者是否有更清洁的方法来实现这一点?谢谢!

代码:

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

示例对象:

{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"}

【问题讨论】:

  • 由于您正在执行自定义排序,IMO,我认为您所拥有的一切都很好。您可以将两种排序方式分解为函数,然后它可以重用,这可能是改进设计的一种方式。但是排序本身,仍然需要实现你所拥有的逻辑。
  • 您要按字母顺序排列在底部还是顶部?
  • 不一定需要class订购。标签本身需要排序(对于搜索过滤器类型),它应该遵循 car_types_order。而对于 search-filter-company,它应该是按字母顺序排列的。
  • 不要寻找“聪明”的技巧来缩短代码,尤其是当它们涉及需要不寻常的隐式类型强制的不直观操作时。更短并不意味着更清晰。您的代码应该清楚地描述您的意图。

标签: javascript jquery arrays object


【解决方案1】:

您可以先检查是否给出了'search-filter-type',然后将这些项目排序到botton,如果两者都给出,则按索引排序,如果相同,则按字母排序。

要将'search-filter-type' 排序到顶部,您可以在此行中交换ab

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

一些更高级的技术:

  • 使用对象来访问汽车类型的顺序。

  • 为未找到的类型采用默认值。这要求不要对已知类型使用虚假值,例如零。

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

【讨论】:

  • 逻辑存在潜在缺陷。只有not 具有"search-filter-type" 类的对象也保证not 具有不匹配的@987654333,它才会可靠地工作@s 在那个数组中。如果这样做,那么它们将按该数组顺序而不是词法排序。
  • ...执行所有那些不必要的.indexOf() 操作也会对性能产生负面影响。
  • @CrazyTrain,数据结构按原样给出。 indexOf 操作可以替换为具有订单类型作为键和索引作为值的对象,如 here 所述,或 here
  • “数据结构原样给出” 你怎么知道?你发这个问题了吗?那是稻草人帐号吗?
  • @CrazyTrain,每个对象在问题中都包含相同的属性。我不认为某些对象缺少某些属性。这不是问题的一部分,如果是的话,应该提及。
【解决方案2】:

不要被“聪明”的 hack 所吸引,这些 hack 提供的短代码变得非常难以解释,因此可能掩盖令人讨厌的错误。

编写清晰、描述性的代码,以便其他人(甚至以后的您自己)能够快速理解其意图。这是一个例子:

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

保证永远不会搜索数组,除非两个对象都具有"search-filter-type" 类。如果两者都没有该类,它也不会执行 .label 的词法比较。


作为潜在性能增强,使用字符串的Map 来订购编号而不是Array 用于car_types_order

此演示以Array 开头,但仅用于构建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; }

【讨论】:

  • 你可能会查看这部分:car_types_order.get(a.label) || 0 - car_types_order.get(b.label) || 0,基本上是car_types_order.get(a.label) || (0 - car_types_order.get(b.label)) || 0。不管怎样,乖一点。
  • @NinaScholz:是的,你是对的。我没有正确考虑优先级。感谢您指出我的代码中的错误。我更新了解决问题的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-11
  • 1970-01-01
  • 2013-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多