如果我有值“foo”,和一个HashMap<String> ftw,其中ftw. containsvalue(“foo”)返回真,我怎么能得到相应的键?我需要遍历hashmap吗?最好的方法是什么?
如果您选择使用Commons Collections库而不是标准的Java Collections框架,则可以轻松实现这一点。
Collections库中的BidiMap接口是一个双向映射,允许您将一个键映射到一个值(像法线映射一样),也允许您将一个值映射到一个键,从而允许您在两个方向上执行查找。getKey()方法支持为值获取键。
但有一个警告,bidi映射不能有多个值映射到键,因此,除非您的数据集在键和值之间有1:1的映射,否则不能使用bidi映射。
如果您希望依赖Java Collections API,那么在将值插入映射时,必须确保键和值之间的1:1关系。说起来容易做起来难。
一旦您能够确保这一点,就可以使用entrySet()方法获取Map中的条目(映射)集。一旦您获得了类型为Map的集合。条目,遍历条目,将存储的值与预期的值进行比较,并获得相应的键。
对带泛型的bidi映射的支持可以在谷歌Guava和重构的Commons-Collections库中找到(后者不是Apache项目)。感谢Esko指出Apache Commons Collections中缺少的泛型支持。使用带有泛型的集合使代码更具可维护性。
从4.0版开始,官方Apache Commons Collections™库支持泛型。
请参阅“org.apache.commons.collections4.bidimap”包的摘要页,了解BidiMap、OrderedBidiMap和SortedBidiMap接口的可用实现列表,这些接口现在支持Java泛型。
我认为你的选择是
Use a map implementation built for this, like the BiMap from google collections. Note that the google collections BiMap requires uniqueless of values, as well as keys, but it provides high performance in both directions performance Manually maintain two maps - one for key -> value, and another map for value -> key Iterate through the entrySet() and to find the keys which match the value. This is the slowest method, since it requires iterating through the entire collection, while the other two methods don't require that.
如果你在自己的代码中构建映射,尝试将map中的键和值放在一起:
public class KeyValue {
public Object key;
public Object value;
public KeyValue(Object key, Object value) { ... }
}
map.put(key, new KeyValue(key, value));
当你有了一个值,你也就有了键。
是的,您必须遍历hashmap,除非您按照这些不同答案所建议的方式实现某些东西。而不是摆弄entrySet,我只获得keySet(),遍历该集合,并保留为您提供匹配值的(第一个)键。如果你需要所有匹配这个值的键,显然你需要做所有的事情。
正如Jonas所建议的,这可能已经是containsValue方法正在做的事情,所以您可以完全跳过这个测试,而只是每次都进行迭代(或者编译器可能已经消除了冗余,谁知道呢)。
另外,相对于其他答案,如果你的反向映射看起来像
Map<Value, Set<Key>>
如果需要这种功能,您可以处理非唯一key->值映射(先解开它们)。这将把fine纳入人们建议的任何解决方案中,使用两张地图。
如果你的数据结构在键和值之间有多对一映射,你应该遍历条目并选择所有合适的键:
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());
}
此外,对于番石榴用户来说,BiMap可能也很有用。例如:
BiMap<Token, Character> tokenToChar =
ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
恐怕你只能重复你的地图了。我能想到的最简短的:
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();
}
}
你可以使用下面的代码获取键值。
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);
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包含唯一键到唯一值的映射,您可以维护一个包含从值到键映射的hashmap。
也就是说你必须维护两个hashmap
1. Key to value
2. Value to key
在这种情况下,您可以使用第二个hashmap来获取key。
使用薄包装: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;
}
}
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);
}
}
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);
}
}
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
*/
}
您可以将键、值对及其逆函数插入到映射结构中
map.put("theKey", "theValue");
map.put("theValue", "theKey");
使用map.get("theValue")将返回"theKey"。
这是一种快速而肮脏的方法,我已经创建了常量映射,它只适用于少数数据集:
只能包含1 ~ 1对 值集与键集不相交(1-> 2,2 ->3中断它)
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();
}
}
在java8
map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
.forEach(entry -> System.out.println(entry.getKey()));
我认为这是最好的解决方案,原始地址: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));
/**
* 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;
}
需要注意的是,由于这个问题,Apache Collections支持通用的BidiMaps。因此,一些投票最多的答案在这一点上不再准确。
对于支持重复值(一对多场景)的Serialized BidiMap,也可以考虑MapDB.org。
for(int key: hm.keySet()) {
if(hm.get(key).equals(value)) {
System.out.println(key);
}
}
使用Java 8:
ftw.forEach((key, value) -> {
if (value.equals("foo")) {
System.out.print(key);
}
});
对于针对API < 19的Android开发,Vitalii Fedorenko一对一关系解决方案无法工作,因为对象。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;
}
用你自己的实现来装饰地图
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);
}
}
我的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)
}
如果你想从value中获取key,最好使用bidimap(双向映射),你可以在O(1)时间内从value中获取key。 但是,这样做的缺点是你只能使用唯一的键集和值集。 在java中有一个数据结构叫Table,它就是map of maps 表< A, B, C > == map < A, map < B, C > > 这里通过查询T.row(a);可以得到map<B,C>,通过查询T.column(B);也可以得到map< a,C>;
在你的特殊情况下,插入C作为某个常数。
它是< a1, b1, 1 > < a2, b2, 1 >,…
如果你通过t。row(a1)——>返回——>的map get keyset这个返回的map。
如果你需要找到键值,那么T.column(b2)——>返回map of——> get keyset of返回map。
与前一种情况相比的优点:
可以使用多个值。 在使用大型数据集时效率更高。
你可以使用下面的:
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);
}
}
}
}
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;
}
我认为keySet()可以很好地找到映射到值的键,并且具有比entrySet()更好的编码风格。
Ex:
假设你有一个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());
}
}
希望能有所帮助。
虽然这并没有直接回答问题,但它是相关的。
这样你就不需要继续创建/迭代了。只需创建一个反向映射一次,就可以得到你需要的东西。
/**
* 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;
}
试试这个:
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()
and
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 w/o使用外部库 一个键可以处理多个值(与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);
}
获取一个包含键映射值的列表 对于1:1映射,返回的列表为空或包含1个值
让我们看看我的例子
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"]
注:未经测试,可能含有错别字
从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(最终操作)来打印最终结果。
找到了太多答案。有些真的很棒。但我特别在寻找一种方法,这样我就可以用循环得到值。
这就是我最后做的: 对于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
-谢谢
推荐文章
- 到底是什么导致了堆栈溢出错误?
- 为什么Android工作室说“等待调试器”如果我不调试?
- Java:路径vs文件
- ExecutorService,如何等待所有任务完成
- Maven依赖Servlet 3.0 API?
- 如何在IntelliJ IDEA中添加目录到应用程序运行概要文件中的类路径?
- getter和setter是糟糕的设计吗?相互矛盾的建议
- Android room persistent: AppDatabase_Impl不存在
- Java的String[]在Kotlin中等价于什么?
- Intellij IDEA上的System.out.println()快捷方式
- 使用Spring RestTemplate获取JSON对象列表
- Spring JPA选择特定的列
- URLEncoder不能翻译空格字符
- Java中的super()
- 如何转换JSON字符串映射<字符串,字符串>与杰克逊JSON