Java Map.containsValue 在列表中的第 15000 项之后不起作用
Java Map.containsValue doesn't work after 15000th item in the list
我有两个 HashMap,每个列表中有 30000 个不同顺序的相同单词。虽然我可以将来自第二个列表的搜索值与第一个列表进行比较,但是在第 15000 个项目之后比较不起作用。我知道哈希图中没有保证,但我不需要顺序,我只是通过列表映射检查搜索图中的单词并删除已创建的单词。如果列表包含搜索中的所有单词,则要 return true。有没有漏掉的地方?
//Sample values (30000 same words with different order):
//list: hooef dalwm vuitg enewb xcbfy ...
//search: dalwm xcbfy hooef enewb dalwm ...
Map<Integer, String> list = new HashMap<Integer, String>();
Map<Integer, String> search = new HashMap<Integer, String>();
boolean check = true;
for(int i=0; i<search.size(); i++) {
if(list.containsValue(search.get(i)))
list.remove(i);
else
check = false; //when i=15000 the code hits to here
}
return check; //returns false
如果映射的键是顺序,那么 list.remove(i);
会从 list
中删除一个随机值,这似乎不正确。
这是一个可能的解决方案:
Collection<String> values = list.values();
for(int i=0; i<search.size(); i++) {
if(!values.remove(search.get(i))) {
check = false;
}
}
containsValue
似乎不起作用的原因是您已经无意中删除了它正在寻找的值。
Assume Search -> 1:A, 2:B, 3:C
List -> 3:B, 1:C, 2:A
List
检查键 1
是否包含 Search's
值。确实如此。它位于 List
中的 key 2
。但是您在 List
处删除了键 1
,认为它是值 A
。但它的价值C
。现在,当 List
检查值 C
时,它将失败。
据我所知,您需要解决三个问题。
- 您正在尝试关联两个本质上具有不同键值映射的映射(尽管它们具有相同的键和值集)。
- 您想根据值而不是键搜索和删除。
- 并且您可以有重复的值。
这是我的方法。第一部分是构建用于测试的数据结构。
Stream<String> stream = null;
try {
stream = Files.lines(Path.of("f:/linux.words"));
} catch (Exception e) {
e.printStackTrace();
}
// limit to 100_000 word
int count = 100_000;
现在确保单词的顺序不同。
String[] words1 = stream.limit(count).toArray(String[]::new);
String[] words2 = words1.clone();
Collections.shuffle(Arrays.asList(words2)); // shuffle the array.
现在构建两个不同的地图search
和list
Map<Integer, String> list = new HashMap<>();
Map<Integer, String> search = new HashMap<>();
for (int i = 0; i < words1.length; i++) {
list.put(i + 1, words1[i]);
search.put(i + 1, words2[i]);
}
现在创建一个 valueToKeyMap
将所有值映射到它们各自的键。由于值可以重复,因此键包含在 List
中
Map<String, List<Integer>> valueToKeyMap = list.entrySet().stream()
.collect(Collectors.groupingBy(Entry::getValue,
Collectors.mapping(Entry::getKey,
Collectors.toList())));
现在遍历地图删除重复项。 valueToKeyMap 中的列表将需要
迭代但预期(可能不正确)任何给定字符串的重复次数将很小(例如,单词 cow
可能只出现 10 次)。
这似乎工作得相当快。包括文件读取等在内的整个工作大约需要 1 秒。该速度的部分原因是没有重复项,因此 keys
的每个 List<Integer>
的长度为 1。
count = 0;
int size = list.size();
for (int i = 1; i <= size; i++) {
String value = search.get(i);
if (valueToKeyMap.containsKey(value)) {
// no need to verify if list contains value, valueToKeyMap was
// created from it.
for (int vkm : valueToKeyMap.get(value)) {
list.remove(vkm);
count++;
}
}
}
System.out.println(list);
System.out.println(list.size());
System.out.println(count);
我有两个 HashMap,每个列表中有 30000 个不同顺序的相同单词。虽然我可以将来自第二个列表的搜索值与第一个列表进行比较,但是在第 15000 个项目之后比较不起作用。我知道哈希图中没有保证,但我不需要顺序,我只是通过列表映射检查搜索图中的单词并删除已创建的单词。如果列表包含搜索中的所有单词,则要 return true。有没有漏掉的地方?
//Sample values (30000 same words with different order):
//list: hooef dalwm vuitg enewb xcbfy ...
//search: dalwm xcbfy hooef enewb dalwm ...
Map<Integer, String> list = new HashMap<Integer, String>();
Map<Integer, String> search = new HashMap<Integer, String>();
boolean check = true;
for(int i=0; i<search.size(); i++) {
if(list.containsValue(search.get(i)))
list.remove(i);
else
check = false; //when i=15000 the code hits to here
}
return check; //returns false
如果映射的键是顺序,那么 list.remove(i);
会从 list
中删除一个随机值,这似乎不正确。
这是一个可能的解决方案:
Collection<String> values = list.values();
for(int i=0; i<search.size(); i++) {
if(!values.remove(search.get(i))) {
check = false;
}
}
containsValue
似乎不起作用的原因是您已经无意中删除了它正在寻找的值。
Assume Search -> 1:A, 2:B, 3:C
List -> 3:B, 1:C, 2:A
List
检查键 1
是否包含 Search's
值。确实如此。它位于 List
中的 key 2
。但是您在 List
处删除了键 1
,认为它是值 A
。但它的价值C
。现在,当 List
检查值 C
时,它将失败。
据我所知,您需要解决三个问题。
- 您正在尝试关联两个本质上具有不同键值映射的映射(尽管它们具有相同的键和值集)。
- 您想根据值而不是键搜索和删除。
- 并且您可以有重复的值。
这是我的方法。第一部分是构建用于测试的数据结构。
Stream<String> stream = null;
try {
stream = Files.lines(Path.of("f:/linux.words"));
} catch (Exception e) {
e.printStackTrace();
}
// limit to 100_000 word
int count = 100_000;
现在确保单词的顺序不同。
String[] words1 = stream.limit(count).toArray(String[]::new);
String[] words2 = words1.clone();
Collections.shuffle(Arrays.asList(words2)); // shuffle the array.
现在构建两个不同的地图search
和list
Map<Integer, String> list = new HashMap<>();
Map<Integer, String> search = new HashMap<>();
for (int i = 0; i < words1.length; i++) {
list.put(i + 1, words1[i]);
search.put(i + 1, words2[i]);
}
现在创建一个 valueToKeyMap
将所有值映射到它们各自的键。由于值可以重复,因此键包含在 List
Map<String, List<Integer>> valueToKeyMap = list.entrySet().stream()
.collect(Collectors.groupingBy(Entry::getValue,
Collectors.mapping(Entry::getKey,
Collectors.toList())));
现在遍历地图删除重复项。 valueToKeyMap 中的列表将需要
迭代但预期(可能不正确)任何给定字符串的重复次数将很小(例如,单词 cow
可能只出现 10 次)。
这似乎工作得相当快。包括文件读取等在内的整个工作大约需要 1 秒。该速度的部分原因是没有重复项,因此 keys
的每个 List<Integer>
的长度为 1。
count = 0;
int size = list.size();
for (int i = 1; i <= size; i++) {
String value = search.get(i);
if (valueToKeyMap.containsKey(value)) {
// no need to verify if list contains value, valueToKeyMap was
// created from it.
for (int vkm : valueToKeyMap.get(value)) {
list.remove(vkm);
count++;
}
}
}
System.out.println(list);
System.out.println(list.size());
System.out.println(count);