【问题标题】:Algorithm to Pick object from list based on object attributes基于对象属性从列表中选择对象的算法
【发布时间】:2015-10-18 02:14:43
【问题描述】:

有一个对象,汽车,它被定义为,

class Cars{
      String make;
      String model;
      String year;
....
}

对Object的几个限制:

  1. 品牌、型号和年份可以取任何值。

  2. 不能有两个具有相同属性集的对象。例如,不能有car1 = { make : "Audi", model : "A6", year : "2008" }car2 = { make : "Audi", model : "A6", year : "2008"}

假设我与一个服务交谈,该服务为我提供了所有汽车对象的列表。我有一个输入(品牌、型号、年份)。我的工作是从列表中选择汽车对象(由服务返回)。我应该这样做,以便我会选择匹配尽可能多的属性的对象。

让我举个例子。假设我从服务中获得了 5 辆汽车的列表,

car1 = { make : "",     model : "A6", year : "2008" }
car2 = { make : "Audi", model : "",   year : "2008" }
car3 = { make : "Audi", model : "A6", year : "" }
car4 = { make : "",     model : "",   year : "" }
car5 = { make : "BMW",  model : "M3", year : "2009" }

如果我的输入是

{make : "Audi", model : "A6", year : "2008"}

我应该只能从列表中选择一辆车。如果相同数量的参数匹配,我应该优先考虑品牌 > 型号 > 年份。在上述情况下,我应该选择 car3。

如果我的输入是

{ make : "Mercedes", model : "C300", year : "2008" }

我应该选择car4 = { make : "", model : "", year : "" }(通用的)

关于解决此问题和/或伪代码的任何建议?

【问题讨论】:

  • 你尝试了什么?如果我有两辆汽车,一辆是{make: 'Audi', model: '', year: ''},一辆是{make : "", model : "A6", year : "2008"},在你的例子中会发生什么?
  • 在这种情况下,我会选择第二个。只有当我们的汽车具有相同数量的匹配参数时,优惠待遇才适用。

标签: java arrays list sorting object


【解决方案1】:

请注意,我们不需要在这里进行任何排序,只需找到最高分即可。排序使您的解决方案O(NlogN),而找到一个最大值是O(N)

public Car getBestSelection(List<Car> cars, String make, String model, String year){
    Map<Car, Integer> scoreMap = new HashMap<>(cars.size());

    // Find scores for all valid cars
    for(Car car : cars)
        if(isValidCar(car, make, model, year))
            scoreMap.push(car, calcScore(car, make, model, year));

    // find max score
    Car maxCar;
    int maxScore;
    for(Map.Entry<Car, Integer> e : scoreMap.entrySet()){
        if(e.getValue() > maxScore){
            maxScore = e.getValue();
            maxCar = e.getKey();
        }
    }

    return maxCar;
}

public int calcScore(Car car, String make, String model, String year){
    int makeScore  = car.make.equals(make)   ? Math.pow(2,2) : 0;
    int modelScore = car.model.equals(model) ? Math.pow(2,1) : 0;
    int yearScore  = car.year.equals(year)   ? Math.pow(2,0) : 0;

    return makeScore + modelScore + yearScore;
}

public boolean isValidCar(Car car, String make, String model, String year){
    return (car.make.equals("") && car.model.equals("") && car.year.equals("")) ||
           (car.make.equals(make) || car.model.equals(model) || car.year.equals(year));
}

【讨论】:

    【解决方案2】:

    我会考虑使用数据库表来存储这些条目:

    Table cars:
    
    |  make  |  model  | year |
    +--------+---------+------+
    |  ...   |   ...   | ...  |
    

    然后您可以使用 SQL 语句选择最佳条目:

    SELECT * FROM cars
    WHERE make  IN('Audi', '')
    AND   model IN('A6',   '')
    AND   year  IN('2008', '')
    SORT BY make DESC, model DESC, year DESC
    LIMIT 1
    

    DESC 是因为否则'' 将首先出现。

    LIMIT 1 是根据您的排序顺序从行中选择最佳候选。


    案例一: {make : "Audi", model : "A6", year : "2008"}

    |  make  |  model  | year |
    +--------+---------+------+
    |  Audi  |   A6    |  ''  |  <--- LIMIT 1 selects this one
    |  Audi  |   ''    | 2008 |
    |   ''   |   A6    | 2008 |
    |   ''   |   ''    |  ''  |
    

    案例2:{ make : "Mercedes", model : "C300", year : "2008" }

    |  make  |  model  | year |
    +--------+---------+------+
    |   ''   |   ''    |  ''  |  <---- LIMIT 1 selects this one
    

    【讨论】:

    • 我确信这是一个同样好的解决方案,但我正在寻找没有数据库的解决方案。
    【解决方案3】:

    第 1 步)找出所有符合您的条件的项目。

    第 2 步)按分数对结果进行排序,将您的标准按重要性排序。

    这是一些 JavaScript 中的伪代码(您可以将其迁移到 Java)。

    var list = [
        {a: "a1", b: "b1", c: "c1"},
        {a: "a1", b: "b1", c: "c2"},
        {a: "a1", b: "b2", c: "c1"},
        {a: "a1", b: "b2", c: "c2"},
        {a: "a2", b: "b1", c: "c1"},
        {a: "a2", b: "b1", c: "c2"},
        {a: "a2", b: "b2", c: "c1"},
        {a: "a2", b: "b2", c: "c2"}
    ];
    
    function findAny(a, b, c) {
        // get a list of all of the items that match any case
        var found = list.filter(function(record) {
            return record.a == a || record.b == b || record.c == c;
        });
        // sort the items be the calculated score high to low
        function score(record) {
            var score = 0;
            if(record.a == a) { score += Math.pow(2, 2); }
            if(record.b == b) { score += Math.pow(2, 1); }
            if(record.c == c) { score += Math.pow(2, 0); }
            // setting the score on the record for education
            record.score = score;
            return score;
        }
        return found.sort(function(a, b) { return score(b) - score(a); });
    }
    
    var result = findAny("a2", "b2", "c2");
    console.log(JSON.stringify(result, null, "\t"));
    

    上面的结果是

    [
        {
            "a": "a2",
            "b": "b2",
            "c": "c2",
            "score": 7
        },
        {
            "a": "a2",
            "b": "b2",
            "c": "c1",
            "score": 6
        },
        {
            "a": "a2",
            "b": "b1",
            "c": "c2",
            "score": 5
        },
        {
            "a": "a2",
            "b": "b1",
            "c": "c1",
            "score": 4
        },
        {
            "a": "a1",
            "b": "b2",
            "c": "c2",
            "score": 3
        },
        {
            "a": "a1",
            "b": "b2",
            "c": "c1",
            "score": 2
        },
        {
            "a": "a1",
            "b": "b1",
            "c": "c2",
            "score": 1
        }
    ]
    

    编辑如果您只想要得分最高的结果。

    function findAnyBest(a, b, c) {
        function score(record) {
            var score = 0;
            if(record.a == a) { score += Math.pow(2, 2); }
            if(record.b == b) { score += Math.pow(2, 1); }
            if(record.c == c) { score += Math.pow(2, 0); }
            return score;
        }
        var highScore = 0;
        var found = [];
        list.forEach(function(record) {
            var currentScore = score(record);
            if(currentScore > highScore) {
                // new high score throw out the old ones
                found = [record];
                highScore = currentScore;
            } else if(currentScore === highScore) {
                found.push(record);
            }
        });
        return found;
    }
    

    【讨论】:

    • 第二个例子失败了。
    【解决方案4】:

    以上答案大多是正确的,但它们实际上并没有解决规范的问题。当使用指数模型来确定汽车的匹配程度时,最高匹配总是会获胜。这意味着仅在品牌上匹配(4 分)将比在模型和年份上匹配(2 + 1 = 3 分)得分更高。这与最初问题的 cmets 应该发生的情况相反。

    最好使用线性模型(例如,make = 4 分,model = 3 分,year = 2 分)。这样,匹配任意两个条件将胜过匹配单个条件。

    【讨论】:

      猜你喜欢
      • 2016-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-12
      • 1970-01-01
      • 2019-09-17
      相关资源
      最近更新 更多