【问题标题】:Javascript array sorting based on multiple criteria (in one iteration)基于多个条件的 Javascript 数组排序(一次迭代)
【发布时间】:2020-05-17 19:33:59
【问题描述】:

我有一系列汽车:

enum Condition {
  New = 1,
  Used = 2
}

type Car = {
  make: string;
  model: string;
  age: number;
  condition: Condition;
};

const cars: Car[] = [
  {id: "1", make: "BMW", model: "E3", age: 12, condition: Condition.Used},
  {id: "2", make: "Audi", model: "A8", age: 4, condition: Condition.Used},
  {id: "3", make: "Mercedes", model: "SLK", age: 0, condition: Condition.New},
  {id: "4", make: "Ford", model: "CMAX", age: 3, condition: Condition.Used},
  {id: "5", make: "Ford", model: "BMAX", age: 0, condition: Condition.New},
  {id: "6", make: "Porsche", model: "Panamera", age: 0, condition: Condition.New},
]

我有一个搜索查询:

const searchQuery: Car = {
  make: "Ford",
  model: "Panamera",
  age: 4,
  condition: Condition.New
}

我想要一个基于这些规则的排序数组:

  • 与品牌(“福特”)完全匹配的商品排在第一位
  • 与模型完全匹配的其余部分(“Panamera”)排在第二位
  • 其余符合年龄=4的条件
  • 其余的都是新的,
  • 最后是任何未通过任何测试的项目

首先我做的是过滤与品牌匹配的数组,然后是模型,然后是年龄,等等...... 然后将生成的数组合并到最终数组(也过滤掉通过多个条件的重复项),但这需要迭代cars 的次数与我拥有的条件数量一样多。 所以我想知道是否有更好的方法可以一次性完成?也许以某种方式使用.sort

【问题讨论】:

  • 请在此处添加您的最小代码/尝试
  • 您是否尝试过使用过滤功能,例如 array.filter(item => item.make === query.make).filter(item => item.model === query.model) ........等等
  • 或者你可以在 1 次迭代中完成 array.filter(item => item.make === query.make && item.model === query.model) 等等
  • @Alopwer 这不是我想要的。这只会过滤汽车以一次匹配所有条件,从而产生一个空数组,因为没有符合所有条件的项目。

标签: javascript arrays sorting


【解决方案1】:

您可以创建一个映射函数来确定您的优先级,然后减去排序中的标准化值。

const Condition = { New: 1, Used: 2 };

const cars = [
  {id: "1", make: "BMW", model: "E3", age: 12, condition: Condition.Used},
  {id: "2", make: "Audi", model: "A8", age: 4, condition: Condition.Used},
  {id: "3", make: "Mercedes", model: "SLK", age: 0, condition: Condition.New},
  {id: "4", make: "Ford", model: "CMAX", age: 3, condition: Condition.Used},
  {id: "5", make: "Ford", model: "BMAX", age: 0, condition: Condition.New},
  {id: "6", make: "Porsche", model: "Panamera", age: 0, condition: Condition.New},
];

const searchQuery = {
  make: "Ford",
  model: "Panamera",
  age: 4,
  condition: Condition.New
};

const prioritize = (car, query) => {
  if (car.make === query.make) return 4;
  if (car.model === query.model) return 3;
  if (car.age === query.age) return 2;
  if (car.condition === query.condition) return 1;
  
  return 0;
};

const sorted = cars.sort((a, b) => {
  const prioA = prioritize(a, searchQuery);
  const prioB = prioritize(b, searchQuery);

  return prioB - prioA;
});

console.log(JSON.stringify(sorted, null, 2));

如果您希望排序适用于多个条件,例如首先制作和模型,您可以添加一个简单的递归检查并增加优先级:

const prioritize = (car, query) => {
  const { make, model, age, condition } = query;

  if (car.make === make) return 4 + prioritize(car, { model, age, condition });
  if (car.model === model) return 3 + prioritize(car, { age, condition });
  if (car.age === age) return 2 + prioritize(car, { condition });
  if (car.condition === condition) return 1;

  return 0;
};

在这里,您只需检查下一行的其他查询选项。

【讨论】:

    【解决方案2】:

    我建议使用不同的方法,先检查想要的第一个排序条件,然后再检查较低的条件。

    这种方法首先使用新条件对 ford 进行排序,而不是仅先进行 ford。

    const
        Condition = { New: 1, Used: 2 },
        cars = [{ id: "1", make: "BMW", model: "E3", age: 12, condition: Condition.Used }, { id: "2", make: "Audi", model: "A8", age: 4, condition: Condition.Used }, { id: "3", make: "Mercedes", model: "SLK", age: 0, condition: Condition.New }, { id: "4", make: "Ford", model: "CMAX", age: 3, condition: Condition.Used }, { id: "5", make: "Ford", model: "BMAX", age: 0, condition: Condition.New }, { id: "6", make: "Porsche", model: "Panamera", age: 0, condition: Condition.New }],
        searchQuery = { make: "Ford", model: "Panamera", age: 4, condition: Condition.New };
    
    cars.sort((a, b) => 
        (b.make === searchQuery.make) - (a.make === searchQuery.make) ||
        (b.model === searchQuery.model) - (a.model === searchQuery.model) ||
        (b.age === searchQuery.age) - (a.age === searchQuery.age) ||
        (b.condition === searchQuery.condition) - (a.condition === searchQuery.condition)
    );
    
    console.log(cars); // 5 4 6 2 3 1 instead of 4 5 6 1 2 3
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • 有趣的解决方案。如果我理解正确,这个解决方案是在先前的条件匹配时使条件“落入”到以后的条件,直到有一个决定性的条件,对吗?不幸的是,这不是我的要求,我必须做公认的解决方案所做的事情(即使你的解决方案更有意义)。不管怎样,谢谢! (顺便说一句,控制台记录 5 4 6 2 3 1 而不是 4 5 6 1 2 3
    【解决方案3】:

    可以认为是优先排序。给出不同的优先级(分)并计算总分。

    JS 版本

    var Condition;
    (function (Condition) {
      Condition[(Condition["New"] = 1)] = "New";
      Condition[(Condition["Used"] = 2)] = "Used";
    })(Condition || (Condition = {}));
    
    const priority = {
      make: 5,
      model: 4,
      age: 3,
      condition: 2,
    };
    const calculatePoint = (obj, params) =>
      Object.entries(obj).reduce((p, [key, value]) => {
        if (value === params[key]) p += priority[key];
        return p;
      }, 0);
    const sortData = (data, params) =>
      data.sort((x, y) => calculatePoint(y, params) - calculatePoint(x, params));
    
    const cars = [{"id":"1","make":"BMW","model":"E3","age":12,"condition":2},{"id":"2","make":"Audi","model":"A8","age":4,"condition":2},{"id":"3","make":"Mercedes","model":"SLK","age":0,"condition":1},{"id":"4","make":"Ford","model":"CMAX","age":3,"condition":2},{"id":"5","make":"Ford","model":"BMAX","age":0,"condition":1},{"id":"6","make":"Porsche","model":"Panamera","age":0,"condition":1}]
    const searchQuery = {
      make: "Ford",
      model: "Panamera",
      age: 4,
      condition: Condition.New,
    };
    console.log(sortData(cars, searchQuery));

    TS 版本

    enum Condition {
      New = 1,
      Used = 2,
    }
    
    type Car = {
      id?: string;
      make: string;
      model: string;
      age: number;
      condition: Condition;
    };
    
    const cars: Car[] = [{"id":"1","make":"BMW","model":"E3","age":12,"condition":2},{"id":"2","make":"Audi","model":"A8","age":4,"condition":2},{"id":"3","make":"Mercedes","model":"SLK","age":0,"condition":1},{"id":"4","make":"Ford","model":"CMAX","age":3,"condition":2},{"id":"5","make":"Ford","model":"BMAX","age":0,"condition":1},{"id":"6","make":"Porsche","model":"Panamera","age":0,"condition":1}]
    ;
    const searchQuery: Car = {
      make: "Ford",
      model: "Panamera",
      age: 4,
      condition: Condition.New,
    };
    
    const priority = {
      make: 5,
      model: 4,
      age: 3,
      condition: 2,
    };
    const calculatePoint = (obj: Car, params: Car) =>
      Object.entries(obj).reduce((p: number, [key, value]) => {
        if (value === params[key]) p += priority[key];
        return p;
      }, 0);
    const sortData = (data: Car[], params: Car) =>
      data.sort(
        (x: Car, y: Car) => calculatePoint(y, params) - calculatePoint(x, params)
      );
    console.log(sortData(cars, searchQuery));

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-25
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      • 2017-06-24
      • 1970-01-01
      • 2011-02-17
      • 2021-03-15
      相关资源
      最近更新 更多