【问题标题】:Classify a list of value through a list of thresholds通过阈值列表对值列表进行分类
【发布时间】:2017-12-07 10:28:10
【问题描述】:

我有一张 <String,Double> 的地图,被视为对 Doubles 列表进行分类的阈值

HashMap<String, Double> map = new Hashmap<>();
map.put(A/B,0.7);
map.put(B/C,0.4);
map.put(C/D,0.3);
map.put(D/E,0.1);

哈希的双精度值用作对给定列表双精度值进行分类的阈值,因此我想将此映射转换为 A、B、C、D 类的列表

Class A : from 0.7
Class B : from 0.4 to 0.7
Class C : from 0.3 to 0.4
Class D : from 0.1 to 0.3
Class E : less than 0.1

您是否知道如何将其作为StringClassifyByValue(HashMap&lt;String, Double&gt; map, Double value){} 方法执行,该方法返回作为参数给出的值对应的类对应的字符串?

ِ例子:

this.StringClassifyByValue(map,0.5)必须返回B。

【问题讨论】:

  • 我喜欢这个概念,非常感谢您的建议和帮助。

标签: java collections hashmap double threshold


【解决方案1】:

一些想法:首先,您的数据结构并不能真正帮助您解决要解决的问题。但这正是数据结构存在的目的:为您提供有用的抽象,使您能够有效地解决“最重要”的问题。

从那里开始,我建议您从创建更好适合您的问题陈述的类开始。你可以从类似的东西开始

public class Interval {

   private final double lowerBoundary;
   private final double upperBoundary;

   public Interval(double lowerBoundary, upperBoundary) {
     this.lowerBoundary = ...
   } 

   public boolean contains(double value) {
     return (value >= lowerBoundary) && (value <=upperBoundary);
   }

与其继续使用Map&lt;String, Double&gt;,不如使用List&lt;Pair&lt;Classification, Interval&gt;&gt; 之类的东西,其中:

  • Pair 可以是一个简单地保存两个属于一起的值的类(而不是使用“通用”对类,您还可以创建自己的自定义类,组合 Classification 和 @ 987654326@)。
  • Classification 在您的示例中代表一个“类”,例如 A、B、C。关键是:出于此类目的使用原始 String 对象时要小心。也许一个简单的字符串现在就可以了,但也许你以后必须进一步增强你的逻辑 - 然后发现“嗯,现在一个简单的字符串不再起作用了,但现在我必须更新很多地方改变它”。

当然:理想情况下,您可以按“间隔”排序上述列表。然后为特定的 double 值查找 Classification 非常简单:

 for (Pair<Classification, Interval> combo : listOfPairs) {
   if (combo.getInterval().contains(value)) {
     return combo.getClassification(); // yeeha found one
   }
 }
 return "nothing found" ... or throw some kind of exception

长话短说:我无法告诉您如何最好地将您现有的地图转换为上述配对对象列表 - 因为我不了解全局。最初可能创建该映射,然后直接构建这样的对象列表。

并且记录一下:如果该地图作为地图存在,因为有其他,更重要的要求......那么如果你真的想继续使用地图+列表,你必须仔细平衡(意味着“双重簿记”),或者如果您将所有上述逻辑放入将您的地图变成列表的某些服务中,进行查找然后丢弃您的数据的这种“其他”表示。

【讨论】:

  • 非常感谢 GhostCar 的贡献,最后我找到了一个非常示例的解决方案,无需使用正则表达式“/”拆分创建新的边界区间 juste 并从先前和当前元素制作边界。我会与公众分享,非常感谢您的帮助
【解决方案2】:
private HashMap<String, HashMap<String, Double>> getMinMaxThreshold(HashMap<String, Double> map) {

        List<Double> threholds = map.values().stream().collect(Collectors.toList());
        HashMap<String,Double >map1= this.sortByValues(map);
        List<String> keys = map1.keySet().stream().collect(Collectors.toList());

        Collections.sort(threholds);
        Collections.reverse(threholds);

        HashMap<String, HashMap<String,Double>> boudaries = new HashMap<>();


        for (int i =0;i<=threholds.size();i++){

            if(i==threholds.size()){
                HashMap<String, Double> testmap = new HashMap<>();
                testmap.put("max",threholds.get(i-1));
                testmap.put("min",0.0);
                boudaries.put(keys.get(keys.size()-1).split("/")[1], testmap);
                System.out.println(threholds.get(i-1)+" ->"+0+" : "+keys.get(keys.size()-1).split("/")[1] );
            }

            else if (i==0){
                HashMap<String, Double> testmap = new HashMap<>();
                testmap.put("max",Math.exp(1000));
                testmap.put("min",threholds.get(i));
                boudaries.put(keys.get(0).split("/")[0], testmap);
                System.out.println(Math.exp(100) +" ->"+threholds.get(i)+" : "+keys.get(0).split("/")[0] );}

            else{
                HashMap<String, Double> testmap = new HashMap<>();
                testmap.put("max",threholds.get(i-1));
                testmap.put("min",threholds.get(i));
                boudaries.put(keys.get(i).split("/")[0], testmap);
            System.out.println(threholds.get(i-1)+" ->"+threholds.get(i)+" : "+keys.get(i).split("/")[0]);}
        }

        System.err.println(boudaries);

        return boudaries;
    }
  1. “键”是一个“列表”,代表 A、B、C、D 类。
  2. 阈值是一个“列表”表示阈值。我们有 使用此阈值来划定界限。
  3. 我按值对阈值图进行排序,以便按降序获取字符串,并与双阈值列表相同,以使它们按相同顺序排列。
  4. 我循环 foreach 元素的阈值.. 对于第一项,它是关于最后一个边界,所以我将 Exp(1000) 和前一个元素作为边界.. 对于最后一个元素,它是关于一个带有 min 的边界0 和 max 阈值的最后一个元素。

  5. 我使用 split 来获取拆分数组的第一个元素,除了最后一项,我使用数组的第二个元素匹配最后一个元素。就是这样

测试:

如果我们有这个“地图”作为输入

{ "YELLOW_DARK/RED_LIGHT" : 0.20459770114942527 , "GREEN_DARK/GREEN_LIGHT" : 0.6226151930261519 , "GREEN_LIGHT/YELLOW_LIGHT" : 0.4632936507936508 , "YELLOW_LIGHT/YELLOW_DARK" : 0.3525246305418719 , "RED_LIGHT/RED_DARK" : 0.027777777777777776}

我的代码会将其转换为:

2.6881171418161356E43 ->0.6226151930261519 : GREEN_DARK
0.6226151930261519 ->0.4632936507936508 : GREEN_LIGHT
0.4632936507936508 ->0.3525246305418719 : YELLOW_LIGHT
0.3525246305418719 ->0.20459770114942527 : YELLOW_DARK
0.20459770114942527 ->0.027777777777777776 : RED_LIGHT
0.027777777777777776 ->0 : RED_DARK

并以HashMap&lt;String, HashMap&lt;String, Double&gt;&gt;返回

{GREEN_LIGHT={min=0.4632936507936508, max=0.6226151930261519}, YELLOW_DARK={min=0.20459770114942527, max=0.3525246305418719}, YELLOW_LIGHT={min=0.3525246305418719, max=0.4632936507936508}, RED_DARK={min=0.0, max=0.027777777777777776}, RED_LIGHT={min=0.027777777777777776, max=0.20459770114942527}, GREEN_DARK={min=0.6226151930261519, max=Infinity}}
{ "GREEN/LIGHT_YELLOW" : 0.5366379310344828 , "YELLOW_DARK/RED_LIGHT" : 0.18349195937745413 , "YELLOW_LIGHT/YELLOW_DARK" : 0.3571428571428571 , "RED_LIGHT/RED_DARK" : 0.08940809968847352}

【讨论】:

  • 不错的附录 :-)
猜你喜欢
  • 1970-01-01
  • 2020-02-29
  • 2021-05-05
  • 1970-01-01
  • 1970-01-01
  • 2020-11-22
  • 2016-10-15
  • 2013-05-27
  • 1970-01-01
相关资源
最近更新 更多