这个周末,我花了几分钟时间讨论一种算法,该算法将采用一个标题(以度为单位)并返回一个基数方向的String(我正在我使用的android指南针应用程序中使用它)。我最终得到的是:
private String headingToString(Float heading) { String strHeading = "?"; Hashtable<String, Float> cardinal = new Hashtable<String, Float>(); cardinal.put("North_1", new Float(0)); cardinal.put("Northeast", new Float(45)); cardinal.put("East", new Float(90)); cardinal.put("Southeast", new Float(135)); cardinal.put("South", new Float(180)); cardinal.put("Southwest", new Float(225)); cardinal.put("West", new Float(270)); cardinal.put("Northwest", new Float(315)); cardinal.put("North_2", new Float(360)); for (String key: cardinal.keySet()) { Float value = cardinal.get(key); if (Math.abs(heading - value) < 30) { strHeading = key; if (key.contains("North_")) { strHeading = "North"; } break; } } return strHeading; }
我的问题是,这是最好的方法吗?尽管我还没有在网上搜索示例,但它必须做过很多次。是否有其他人尝试过此方法并找到了更整洁的解决方案?
编辑The Reverand’s Thilo’s,shinjin’s和Chrstoffer的回复:
解决方案
public static String headingToString2(double x) { String directions[] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"}; return directions[ (int)Math.round(( ((double)x % 360) / 45)) ]; }
在大多数情况下,这很好,尽管要使其优化和(IMO)更加清洁,您可以做的是找到一个将输入标题与地图中使用的标题相关联的函数。
例如:(我很确定这是正确的,但是您需要检查一下)
45* (int)Math.round(( ((double)x % 360) / 45))
首先x % 360,要确保标题在有效范围内。然后
x % 360
45 * round(.../45)
查找最接近的45的倍数。
现在将地图更改为
HashMap<Integer, String> map = new HashMap<Integer, String>() map.put(0, "North") map.put(45, "Northeast") etc...
因此,现在您的算法成为一种快速的数学计算,而不是遍历整个地图。此外,这里不需要Hashtable,因为它提供了并发构造(如果我没记错的话),并且在您的情况下,这实际上会导致性能下降。
同样,对于您的需求,性能影响可能完全可以忽略不计。
编辑Thilo和shinjin的建议:
不用乘以45,只需保留方程式的其余部分,即为您提供0-7的值,并创建一个字符串数组。
String directions[] = {"N", "NE", "E", "SE", "S", "SW", "W", "NW"} return directions[ (int)Math.round(( ((double)x % 360) / 45)) % 8 ]
并且您的问题已经两行解决了。
注意事项:负数不能正确使用模量。如果我们的输入标题为负,则需要首先使其为正。