如果我有 value"foo"
和 a HashMap<String> ftw
for which ftw.containsValue("foo")
returns true
,我怎样才能得到相应的键?我必须遍历哈希图吗?最好的方法是什么?
39 回答
如果您的数据结构在键和值之间具有多对一映射,则应遍历条目并选择所有合适的键:
public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
Set<T> keys = new HashSet<T>();
for (Entry<T, E> entry : map.entrySet()) {
if (Objects.equals(value, entry.getValue())) {
keys.add(entry.getKey());
}
}
return keys;
}
在一对一关系的情况下,您可以返回第一个匹配的键:
public static <T, E> T getKeyByValue(Map<T, E> map, E value) {
for (Entry<T, E> entry : map.entrySet()) {
if (Objects.equals(value, entry.getValue())) {
return entry.getKey();
}
}
return null;
}
在 Java 8 中:
public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
return map.entrySet()
.stream()
.filter(entry -> Objects.equals(entry.getValue(), value))
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
}
此外,对于 Guava 用户,BiMap可能很有用。例如:
BiMap<Token, Character> tokenToChar =
ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
如果您选择使用Commons Collections 库而不是标准的 Java Collections 框架,您可以轻松实现这一点。
Collections 库中的BidiMap
接口是一个双向映射,允许您将键映射到值(如法线贴图),也可以将值映射到键,从而允许您在两个方向上执行查找。该方法支持获取值的键getKey()
。
但是有一个警告,双向映射不能将多个值映射到键,因此除非您的数据集在键和值之间具有 1:1 映射,否则您不能使用双向映射。
如果要依赖 Java Collections API,则必须在将值插入映射时确保键和值之间的 1:1 关系。这说起来容易做起来难。
一旦可以确保,使用该entrySet()
方法获取 Map 中的一组条目(映射)。获取类型为 的集合Map.Entry
后,遍历条目,将存储的值与预期值进行比较,并获取对应的键。
可以在Google Guava和重构的Commons-Collections库(后者不是 Apache 项目)中找到对带有泛型的双向地图的支持。感谢 Esko 指出 Apache Commons Collections 中缺少的通用支持。使用带有泛型的集合可以使代码更易于维护。
从4.0 版开始,官方 Apache Commons Collections™ 库支持泛型。
请参阅“ org.apache.commons.collections4.bidimap ”包的摘要页面以获取可用的实现列表,以及现在支持 Java泛型的接口。BidiMap
OrderedBidiMap
SortedBidiMap
public class NewClass1 {
public static void main(String[] args) {
Map<Integer, String> testMap = new HashMap<Integer, String>();
testMap.put(10, "a");
testMap.put(20, "b");
testMap.put(30, "c");
testMap.put(40, "d");
for (Entry<Integer, String> entry : testMap.entrySet()) {
if (entry.getValue().equals("c")) {
System.out.println(entry.getKey());
}
}
}
}
一些附加信息...可能对您有用
如果您的哈希图非常大,上述方法可能不太好。如果您的 hashmap 包含唯一键到唯一值的映射,您可以再维护一个包含从值到键的映射的 hashmap。
那就是你必须维护两个哈希图
1. Key to value
2. Value to key
在这种情况下,您可以使用第二个哈希图来获取密钥。
您可以将键、值对及其逆对插入您的地图结构
map.put("theKey", "theValue");
map.put("theValue", "theKey");
然后使用 map.get("theValue") 将返回“theKey”。
这是我制作常量映射的一种快速而肮脏的方式,它只适用于少数几个数据集:
- 仅包含 1 对 1 对
- 值集与键集不相交(1->2、2->3 破坏它)
我认为你的选择是
- 使用为此构建的地图实现,例如来自 google 收藏的BiMap 。请注意,谷歌集合 BiMap 需要唯一的值和键,但它提供了双向性能的高性能
- 手动维护两个映射 - 一个用于 key -> value,另一个用于 value -> key
- 遍历
entrySet()
and 以找到与该值匹配的键。这是最慢的方法,因为它需要遍历整个集合,而其他两种方法不需要。
使用 Java 8:
ftw.forEach((key, value) -> {
if (value.equals("foo")) {
System.out.print(key);
}
});
用你自己的实现装饰地图
class MyMap<K,V> extends HashMap<K, V>{
Map<V,K> reverseMap = new HashMap<V,K>();
@Override
public V put(K key, V value) {
// TODO Auto-generated method stub
reverseMap.put(value, key);
return super.put(key, value);
}
public K getKey(V value){
return reverseMap.get(value);
}
}
没有明确的答案,因为多个键可以映射到同一个值。如果您使用自己的代码强制执行唯一性,最好的解决方案是创建一个使用两个 Hashmap 的类来跟踪两个方向的映射。
要查找映射到该值的所有键,请使用 . 遍历哈希图中的所有对map.entrySet()
。
如果您在自己的代码中构建地图,请尝试将地图中的键和值放在一起:
public class KeyValue {
public Object key;
public Object value;
public KeyValue(Object key, Object value) { ... }
}
map.put(key, new KeyValue(key, value));
然后,当您拥有价值时,您也拥有钥匙。
我认为这是最好的解决方案,原地址:Java2s
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] argv) {
Map<String, String> map = new HashMap<String, String>();
map.put("1","one");
map.put("2","two");
map.put("3","three");
map.put("4","four");
System.out.println(getKeyFromValue(map,"three"));
}
// hm is the map you are trying to get value from it
public static Object getKeyFromValue(Map hm, Object value) {
for (Object o : hm.keySet()) {
if (hm.get(o).equals(value)) {
return o;
}
}
return null;
}
}
一个简单的用法:如果您将所有数据放入 hasMap 并且您有 item = "Automobile",那么您将在 hashMap 中查找它的键。这是一个很好的解决方案。
getKeyFromValue(hashMap, item);
System.out.println("getKeyFromValue(hashMap, item): "+getKeyFromValue(hashMap, item));
恐怕你只需要迭代你的地图。我能想到的最短的:
Iterator<Map.Entry<String,String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String,String> entry = iter.next();
if (entry.getValue().equals(value_you_look_for)) {
String key_you_look_for = entry.getKey();
}
}
for(int key: hm.keySet()) {
if(hm.get(key).equals(value)) {
System.out.println(key);
}
}
听起来最好的方法是让您使用迭代条目,map.entrySet()
因为map.containsValue()
无论如何可能都会这样做。
对于针对 API < 19 的 Android 开发,Vitalii Fedorenko 一对一关系解决方案不起作用,因为Objects.equals
没有实施。这是一个简单的替代方案:
public <K, V> K getKeyByValue(Map<K, V> map, V value) {
for (Map.Entry<K, V> entry : map.entrySet()) {
if (value.equals(entry.getValue())) {
return entry.getKey();
}
}
return null;
}
您可以使用以下内容:
public class HashmapKeyExist {
public static void main(String[] args) {
HashMap<String, String> hmap = new HashMap<String, String>();
hmap.put("1", "Bala");
hmap.put("2", "Test");
Boolean cantain = hmap.containsValue("Bala");
if(hmap.containsKey("2") && hmap.containsValue("Test"))
{
System.out.println("Yes");
}
if(cantain == true)
{
System.out.println("Yes");
}
Set setkeys = hmap.keySet();
Iterator it = setkeys.iterator();
while(it.hasNext())
{
String key = (String) it.next();
if (hmap.get(key).equals("Bala"))
{
System.out.println(key);
}
}
}
}
我认为keySet()可能很好地找到映射到值的键,并且具有比entrySet()更好的编码风格。
前任:
假设你有一个 HashMap映射,ArrayList res,一个你想找到所有键映射到的值,然后将键存储到res。
您可以在下面编写代码:
for (int key : map.keySet()) {
if (map.get(key) == value) {
res.add(key);
}
}
而不是使用下面的 entrySet():
for (Map.Entry s : map.entrySet()) {
if ((int)s.getValue() == value) {
res.add((int)s.getKey());
}
}
希望能帮助到你 :)
是的,您必须遍历哈希图,除非您按照这些不同答案的建议来实现某些东西。与其摆弄 entrySet,我只需获取 keySet(),迭代该集合,并保留为您提供匹配值的(第一个)键。如果您需要与该值匹配的所有键,显然您必须完成整个操作。
正如 Jonas 建议的那样,这可能已经是 containsValue 方法正在做的事情,因此您可能会一起跳过该测试,并且每次都进行迭代(或者编译器可能已经消除了冗余,谁知道呢)。
此外,相对于其他答案,如果您的反向地图看起来像
Map<Value, Set<Key>>
如果您需要该功能(将它们放在一边),您可以处理非唯一键-> 值映射。这将很好地融入人们在这里使用两张地图提出的任何解决方案中。
您可以使用以下代码使用值获取密钥..
ArrayList valuesList = new ArrayList();
Set keySet = initalMap.keySet();
ArrayList keyList = new ArrayList(keySet);
for(int i = 0 ; i < keyList.size() ; i++ ) {
valuesList.add(initalMap.get(keyList.get(i)));
}
Collections.sort(valuesList);
Map finalMap = new TreeMap();
for(int i = 0 ; i < valuesList.size() ; i++ ) {
String value = (String) valuesList.get(i);
for( int j = 0 ; j < keyList.size() ; j++ ) {
if(initalMap.get(keyList.get(j)).equals(value)) {
finalMap.put(keyList.get(j),value);
}
}
}
System.out.println("fianl map ----------------------> " + finalMap);
使用薄包装:HMap
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class HMap<K, V> {
private final Map<K, Map<K, V>> map;
public HMap() {
map = new HashMap<K, Map<K, V>>();
}
public HMap(final int initialCapacity) {
map = new HashMap<K, Map<K, V>>(initialCapacity);
}
public boolean containsKey(final Object key) {
return map.containsKey(key);
}
public V get(final Object key) {
final Map<K, V> entry = map.get(key);
if (entry != null)
return entry.values().iterator().next();
return null;
}
public K getKey(final Object key) {
final Map<K, V> entry = map.get(key);
if (entry != null)
return entry.keySet().iterator().next();
return null;
}
public V put(final K key, final V value) {
final Map<K, V> entry = map
.put(key, Collections.singletonMap(key, value));
if (entry != null)
return entry.values().iterator().next();
return null;
}
}
public static class SmartHashMap <T1 extends Object, T2 extends Object> {
public HashMap<T1, T2> keyValue;
public HashMap<T2, T1> valueKey;
public SmartHashMap(){
this.keyValue = new HashMap<T1, T2>();
this.valueKey = new HashMap<T2, T1>();
}
public void add(T1 key, T2 value){
this.keyValue.put(key, value);
this.valueKey.put(value, key);
}
public T2 getValue(T1 key){
return this.keyValue.get(key);
}
public T1 getKey(T2 value){
return this.valueKey.get(value);
}
}
在java8中
map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
.forEach(entry -> System.out.println(entry.getKey()));
public static String getKey(Map<String, Integer> mapref, String value) {
String key = "";
for (Map.Entry<String, Integer> map : mapref.entrySet()) {
if (map.getValue().toString().equals(value)) {
key = map.getKey();
}
}
return key;
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class M{
public static void main(String[] args) {
HashMap<String, List<String>> resultHashMap = new HashMap<String, List<String>>();
Set<String> newKeyList = resultHashMap.keySet();
for (Iterator<String> iterator = originalHashMap.keySet().iterator(); iterator.hasNext();) {
String hashKey = (String) iterator.next();
if (!newKeyList.contains(originalHashMap.get(hashKey))) {
List<String> loArrayList = new ArrayList<String>();
loArrayList.add(hashKey);
resultHashMap.put(originalHashMap.get(hashKey), loArrayList);
} else {
List<String> loArrayList = resultHashMap.get(originalHashMap
.get(hashKey));
loArrayList.add(hashKey);
resultHashMap.put(originalHashMap.get(hashKey), loArrayList);
}
}
System.out.println("Original HashMap : " + originalHashMap);
System.out.println("Result HashMap : " + resultHashMap);
}
}
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class ValueKeysMap<K, V> extends HashMap <K,V>{
HashMap<V, Set<K>> ValueKeysMap = new HashMap<V, Set<K>>();
@Override
public boolean containsValue(Object value) {
return ValueKeysMap.containsKey(value);
}
@Override
public V put(K key, V value) {
if (containsValue(value)) {
Set<K> keys = ValueKeysMap.get(value);
keys.add(key);
} else {
Set<K> keys = new HashSet<K>();
keys.add(key);
ValueKeysMap.put(value, keys);
}
return super.put(key, value);
}
@Override
public V remove(Object key) {
V value = super.remove(key);
Set<K> keys = ValueKeysMap.get(value);
keys.remove(key);
if(keys.size() == 0) {
ValueKeysMap.remove(value);
}
return value;
}
public Set<K> getKeys4ThisValue(V value){
Set<K> keys = ValueKeysMap.get(value);
return keys;
}
public boolean valueContainsThisKey(K key, V value){
if (containsValue(value)) {
Set<K> keys = ValueKeysMap.get(value);
return keys.contains(key);
}
return false;
}
/*
* Take care of argument constructor and other api's like putAll
*/
}
/**
* This method gets the Key for the given Value
* @param paramName
* @return
*/
private String getKeyForValueFromMap(String paramName) {
String keyForValue = null;
if(paramName!=null)) {
Set<Entry<String,String>> entrySet = myMap().entrySet();
if(entrySet!=null && entrySet.size>0) {
for(Entry<String,String> entry : entrySet) {
if(entry!=null && paramName.equalsIgnoreCase(entry.getValue())) {
keyForValue = entry.getKey();
}
}
}
}
return keyForValue;
}
我的 2 美分。您可以获取数组中的键,然后循环遍历数组。如果地图非常大,这将影响此代码块的性能,其中您首先获取数组中的键,这可能会消耗一些时间,然后您正在循环。否则对于较小的地图应该没问题。
String[] keys = yourMap.keySet().toArray(new String[0]);
for(int i = 0 ; i < keys.length ; i++){
//This is your key
String key = keys[i];
//This is your value
yourMap.get(key)
}
虽然这并不能直接回答问题,但它是相关的。
这样您就不需要继续创建/迭代。只需创建一次反向地图即可获得所需的内容。
/**
* Both key and value types must define equals() and hashCode() for this to work.
* This takes into account that all keys are unique but all values may not be.
*
* @param map
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<V, List<K>> reverseMap(Map<K,V> map) {
if(map == null) return null;
Map<V, List<K>> reverseMap = new ArrayMap<>();
for(Map.Entry<K,V> entry : map.entrySet()) {
appendValueToMapList(reverseMap, entry.getValue(), entry.getKey());
}
return reverseMap;
}
/**
* Takes into account that the list may already have values.
*
* @param map
* @param key
* @param value
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, List<V>> appendValueToMapList(Map<K, List<V>> map, K key, V value) {
if(map == null || key == null || value == null) return map;
List<V> list = map.get(key);
if(list == null) {
List<V> newList = new ArrayList<>();
newList.add(value);
map.put(key, newList);
}
else {
list.add(value);
}
return map;
}
从 Map 中获取给定值的键的最简单实用方法:
public static void fetchValue(Map<String, Integer> map, Integer i)
{
Stream stream = map.entrySet().stream().filter(val-> val.getValue().equals(i)).map(Map.Entry::getKey);
stream.forEach(System.out::println);
}
详细解释:
方法 fetchValue 接受映射,其中 String 作为键,Integer 作为值。
然后我们使用 entryset().stream() 将结果转换为流。
接下来我们使用过滤器(中间操作),它给我们一个等于第二个参数的值。
最后,我们使用 forEach(final operation) 来打印我们的最终结果。
需要注意的是,由于这个问题,Apache Collections 支持Generic BidiMaps。因此,在这一点上,一些投票最多的答案不再准确。
对于同样支持重复值(一对多场景)的序列化 BidiMap,也可以考虑MapDB.org。
如果你想从 value 中获取 key,最好使用 bidimap (bi-directional maps) ,你可以在 O(1) 时间内从 value 中获取 key。
但是,这样做的缺点是您只能使用唯一的键集和值集。
java中有一种叫做Table的数据结构,就是map之类的map
表< A, B, C > == map < A , map < B, C >>
这里可以
map<B,C>
查询得到T.row(a);
,也可以map<A,C>
查询得到T.column(b);
在您的特殊情况下,插入 C 作为某个常量。
所以,它就像 < a1, b1, 1 > < a2, b2 , 1 > , ...
因此,如果您通过 T.row(a1) 找到 ---> 返回映射 --> 获取 keyset 这个返回的映射。
如果您需要查找键值,则 T.column(b2) --> 返回映射 --> 获取返回映射的键集。
与前一种情况相比的优点:
- 可以使用多个值。
- 使用大型数据集时效率更高。
试试这个:
static String getKeyFromValue(LinkedHashMap<String, String> map,String value) {
for (int x=0;x<map.size();x++){
if( String.valueOf( (new ArrayList<String>(map.values())).get(x) ).equals(value))
return String.valueOf((new ArrayList<String>(map.keySet())).get(x));
}
return null;
}
据我所知,当您将 HashMap 的键和值表示为数组时,它们不会混合:
hashmap.values().toArray()
和
hashmap.keySet().toArray()
因此,以下代码(自 java 8 起)应按预期工作:
public Object getKeyByFirstValue(Object value) {
int keyNumber = Arrays.asList(hashmap.values().toArray()).indexOf(value);
return hashmap.keySet().toArray()[keyNumber];
}
但是,(警告!)它的工作速度比迭代慢 2-3 倍。
设值为maxValue
。
Set keySet = map.keySet();
keySet.stream().filter(x->map.get(x)==maxValue).forEach(x-> System.out.println(x));
不使用外部库的 lambda
可以处理一个键的多个值(与 BidiMap 不同)
public static List<String> getKeysByValue(Map<String, String> map, String value) {
List<String> list = map.keySet().stream()
.collect(groupingBy(k -> map.get(k))).get(value);
return (list == null ? Collections.emptyList() : list);
}
获取List
包含1:1key(s)
映射value
的映射返回的列表是empty
或包含 1value
让我们看看我的例子
Map<String, String> mapPeopleAndCountry = new HashMap<>();
mapPeopleAndCountry.put("Matis", "Lithuania");
mapPeopleAndCountry.put("Carlos", "Honduras");
mapPeopleAndCountry.put("Teboho", "Lesotho");
mapPeopleAndCountry.put("Marielos", "Honduras");
List<String> peopleInHonduras = mapPeopleAndCountry.keySet()
.stream()
.filter(r -> mapPeopleAndCountry.get(r)
.equals("Honduras"))
.stream(Collectors.toList());
// will return ["Carlos", "Marielos"]
注意:未经测试,可能包含错字
找到太多答案了。有些真的很棒。但我特别在寻找一种方法,这样我就可以使用循环来获取值。
所以这就是我最终所做的:对于 HashMap 1 对 1 关系:
Map<String, String> map = new HashMap<String, String>();
map.put("abc", "123");
map.put("xyz", "456");
for(Entry<String, String> entry : map.entrySet()) {
if(entry.getValue().equalsIgnoreCase("456")) {
System.out.println(entry.getKey());
}
}
输出:“xyz”
对于 HashMap 一对多关系:
Map<String, ArrayList<String>> service = new HashMap<String, ArrayList<String>>();
service.put("abc", new ArrayList<String>());
service.get("abc").add("a");
service.get("abc").add("b");
service.get("abc").add("c");
service.put("xyz", new ArrayList<String>());
service.get("xyz").add("x");
service.get("xyz").add("y");
service.get("xyz").add("z");
for(Entry<String, ArrayList<String>> entry : service.entrySet()) {
ArrayList<String> values = entry.getValue();
for(String value : values) {
if(value.equalsIgnoreCase("x")) {
System.out.println(entry.getKey());
}
}
}
输出:xyz
-谢谢
Iterator<Map.Entry<String,String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String,String> entry = iterator.next();
if (entry.getValue().equals(value_you_look_for)) {
String key_you_look_for = entry.getKey();
}
}
您也可以这样做:第一:放置 map (key, value) 第二:更新您需要删除表达式的键第三:并使用 oldValue 放置一个新键