在下面,您可以看到我的代码段,在其中我试图识别给定电话号码的原产国。问题在于它总是返回比较字符串值的最后一个键。
我已按值对我的HashMap进行了排序,然后使用startWith方法将给定的String与HashMap中的每个值进行了比较。
import java.util.Comparator;
import java.util.Map;
import java.util.HashMap;
import java.util.Map.Entry;
import javax.swing.JOptionPane;
public class CountryFinder {
static Map<String, String> countriesNamesAndCodes;
public static void main(String[] args) {
countriesNamesAndCodes = new HashMap<>();
countriesNamesAndCodes.put("Greece", "30");
countriesNamesAndCodes.put("Italy", "39");
countriesNamesAndCodes.put("Germany", "49");
countriesNamesAndCodes.put("USA", "1");
countriesNamesAndCodes.put("UK", "44");
countriesNamesAndCodes.put("Bahamas", "1-242");
countriesNamesAndCodes.put("ExampleCountry", "301");
for (Entry<String, String> entry : countriesNamesAndCodes.entrySet()) {
if (entry.getValue().contains("-")) {
String tempValue = entry.getValue().replaceAll("-", "");
entry.setValue(tempValue);
}
}
countriesNamesAndCodes.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.forEach(System.out::println);
String input = String.valueOf(JOptionPane.showInputDialog("Type a telephone number"));
System.out.println(input);
System.out.println("Origin Country: " + getCountry(input));
}
private static String getCountry(String telephoneNumber) {
for (Entry<String, String> entry : countriesNamesAndCodes.entrySet()){
if (telephoneNumber.startsWith(entry.getValue())) {
return (entry.getKey());
}
}
return null;
}
}
当输入为1242888999或1-242888999时,我希望输出为“巴哈马”,但实际输出为“美国”。输入301555666也是如此,我希望使用“ ExampleCountry”而不是“ Greece”。
答案 0 :(得分:0)
我不认为这一行可以使HashMap
保持排序:它仅对要打印的流进行排序。
countriesNamesAndCodes.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.forEach(System.out::println);
这意味着以后再遍历地图的条目集时,您将受其遍历哈希地图的顺序的约束,而Java对此顺序不做任何保证(the documentation甚至说该顺序可能随时间变化)。
您可能想查看SortedMap。
答案 1 :(得分:0)
HashMap
未排序。您不能依赖它的顺序,因为它主要基于hashCode()
。
但是,您的问题与订单无关,这是因为您没有选择最长的前缀(具有最大长度的值):如果您查找1-242,则查找USA(1)和巴哈马(1-242) )的作品。 ExampleCountry(301)和希腊(30)也是如此。
您的算法应该是这样的:对于每个电话号码以该条目的值开头的条目,我们记住“最佳匹配”条目,并在从未发现(初始情况)或它的值是比以前匹配的大。
private static String getCountry(String telephoneNumber) {
var bestMatch = null; // Map.Entry<String,String>
for (Entry<String, String> entry : countriesNamesAndCodes.entrySet()){
if (telephoneNumber.startsWith(entry.getValue()) {
if (bestMatch == null || entry.getValue().length() > bestMatch.getValue().length()) {
bestMatch = entry;
}
}
}
return null != bestMatch ? bestMatch.getKey():null;
}
答案 2 :(得分:0)
您的代码完全按照编写的代码执行,您的问题在这里
private static String getCountry(String telephoneNumber) {
for (Entry<String, String> entry : countriesNamesAndCodes.entrySet()){
if (telephoneNumber.startsWith(entry.getValue())) {
return (entry.getKey());
}
}
return null;
}
您要提取的第一个搜索匹配项值在您的情况下(1-242888999)以1开头,因此它将带来项= 1,即USA。
原因是因为您正在使用流进行订购,并且当您输入getCountry时又再次出现了故障,因此您需要先保存订购。
答案 3 :(得分:0)
结合其他一些答案中的元素,您可能希望将SortedMap
从国家/地区代码到国家/地区的名称保持一致,并以降序排列(按字母顺序打断领带)。>
这样,始终会首先检查最长匹配项,因此不会遇到相同的前缀问题。
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import static java.util.Map.Entry;
import static java.util.Comparator.comparingInt;
import static java.util.Comparator.naturalOrder;
class Example {
public static void main(String[] args) {
SortedMap<String, String> codeCountries = new TreeMap<>(
comparingInt(String::length)
.reversed()
.thenComparing(naturalOrder()));
codeCountries.putAll(Map.of(
"1", "United States",
"1241", "Bahamas",
));
for (String name : codeCountries.values) {
System.out.println(name);
// Prints "United States", then "Bahamas"
}
}
}
您唯一需要进行的其他更改是,您必须先将国家/地区破折号 中的破折号删除后再放入地图中。如果您不这样做,那么这两个键都将保留在地图中。
作为一种类似的,可能更快(但不是真的快得多)的替代方法,您可以保留未分类的地图,并以国家/地区代码为键,并且每当您输入信息时,都可以尝试获取来自地图的所有前缀:
Map<String, String> countryCodes = Map.of("1242", "Bahamas", "1", "United States");
String input = /* get some input */;
for (int i = input.length; i > 0; --i) {
String country = countryCodes.get(input.substring(0, i));
if (country != null) {
return country;
}
}
// If you get here, no country code was found in the map.
// Alternatively, with streams:
IntStream.range(0, input.length())
.mapToObj(i -> input.substring(0, input.length() - i))
.filter(countryCodes::containsKey)
.findFirst();
但是,比担心解析国家/地区代码或检测国家/地区代码之间的重叠(尤其是如果您的用户有时忘记包括其国家/地区代码)更可靠的想法是,先要求国家/地区代码,然后再要求其余的国家/地区代码。然后,您可以直接查找国家/地区代码,而不必担心重叠。
答案 4 :(得分:0)
我编写了一个新方法,并尝试将临时Stream顺序保存在另一个Map中。现在可以了!
private static Map<String, String> sortMapByValuesDesc(Map<String, String> unsortedMap) {
return sortedMap = unsortedMap
.entrySet()
.stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.collect(
toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2, LinkedHashMap::new));
}