检查List是否是HashMap中的值

时间:2015-10-03 16:51:07

标签: java list hashmap

我想检查一个值是否存在。

我的代码:

public static final Map<String, List<String>> m = new HashMap<>();

if(m.containsValue("gummi")) {...}

我的问题是该值是一个List。 如何查看列表?

14 个答案:

答案 0 :(得分:13)

因此,我要解释这个问题,是想知道Map的任何值是否包含目标String

可能有一个更合适的第三方双向多图实现。如果您将来要阅读此内容,则Java SE中可能有这种类型-请编辑此答案。

鉴于数据结构,这将需要搜索整个数据。让Map用另一种方式映射可能更好。让我们忽略它。

流单线表达解决方案:

m.values().stream().anyMatch(list -> list.contains("gummi"))

编辑:对于Horse Voice(非流媒体版本)。

flatContains(m.values(), "gummi")

其中

public static boolean flatContains(
    Iterable<? extends Collection<?>> collections,
    Object value
) {
    for (Collection<?> collection : collections) {
        if (collection.contains(value)) {
            return true;
        }
    }
    return false;
}

通常避免使用流,从​​而使代码更具可读性(并且速度更快)。但是,在这种情况下,我会直奔潮流。如果涉及flatMap,那么选择将更加接近。

答案 1 :(得分:2)

Map<String, List<String>> m = new HashMap<>();

    List<String> list1 = new ArrayList<>();
    List<String> list2 = new ArrayList<>();
    List<String> list3 = new ArrayList<>();

    m.put("1", list1);
    m.put("2", list2);

    System.out.println(m.containsValue(list1));
    System.out.println(m.containsValue(list2));
    System.out.println(m.containsValue(list3));

输出

true
true
true

说明

只要新列表为空,哈希码值始终为1 。因此list1,list2和list3的哈希码值都为1。基本上,

list1 = list2 = list3

所以即使我们检查m.containsValue(list3);它将返回 true 。但是,如果列表不为空,则每个列表将具有唯一的哈希码。因此,只要您的地图具有非空列表,我们就可以使用containsValue(listObject)来返回正确的结果。以下示例,

Map<String, List<String>> m = new HashMap<>();

    List<String> list1 = new ArrayList<>();
    List<String> list2 = new ArrayList<>();
    List<String> list3 = new ArrayList<>();

    list1.add("apple");
    list1.add("orange");

    list2.add("mobile");
    list2.add("computer");

    m.put("1", list1);
    m.put("2", list2);

    System.out.println(m.containsValue(list1));
    System.out.println(m.containsValue(list2));
    System.out.println(m.containsValue(list3));

输出:

true
true
false

其他用例:

如果我们要检查地图中的值是否为列表类型,或者我们要检查列表中的一个值是否存在,则可以如下迭代地图,

for (String key : m.keySet()) {
        if (m.get(key) instanceof List) {
            for (String listItem : m.get(key)) {
                if ("valueWeSearchFor".equalsIgnoreCase(listItem)) {
                    break;
                }
            }
        }else{
            //If the value in the map is not of type list
            //What to do!!
        }
    }

答案 2 :(得分:1)

引自List.equals Javadoc:

  

换句话说,如果两个列表包含相同顺序的相同元素,则它们被定义为相等。

因此,要检查值是否存在,您可以创建一个列表并使用List调用containsValue,因为此方法将调用equals来确定相等性。如果相同的元素具有相同的顺序,则会找到匹配项。

您可以使用Arrays.asList

轻松地从值数组中创建List
if(m.containsValue(Arrays.asList("gummi"))) {...}

示例代码:

Map<String, List<String>> m = new HashMap<>();
List<String> list = new ArrayList<>();

list.add("1");
list.add("2");
m.put("key", list);

if (m.containsValue(Arrays.asList("1", "2"))) {
    System.out.println("contains value");
}

答案 3 :(得分:1)

Java 7:contains的{​​{1}}

假设与Tom相同,这是Java 7版本(根据Horse Voice的要求):

Map<String, List<String>>

如果您的源Map不变,那么可能创建搜索缓存会更好:

// Live version
static boolean contains(Map<String, List<String>> map, String value) {
    for (List<String> list : map.values()) {
        if(list.contains(value)) return true;
    }
    return false;
}

Java 7:// Cached version private List<String> allValues = getInnerValues(map); private List<String> getInnerValues(Map<String, List<String>> map) { List<String> result = new ArrayList<>(); for (List<String> list : map.values()) { result.addAll(list); } return result; } static boolean contains(String value) { return allValues.contains(value); } anyKeyForValue

我认为有些人会想要与值匹配的键:

keysForValue

缓存有点困难;我们需要反转地图:

// Live version
static String anyKeyForValue(Map<String, List<String>> map, String value) {
    for (Entry<String, List<String>> entry : map.entrySet()) {
        if(entry.getValue().contains(value)) return entry.getKey();
    }
    return null;
}

static List<String> keysForValue(Map<String, List<String>> map, String value) {
    List<String> result = new ArrayList<>();
    for (Entry<String, List<String>> entry : map.entrySet()) {
        if(entry.getValue().contains(value)) result.add(entry.getKey());
    }
    return result;
}

答案 4 :(得分:0)

@Tom的答案是最好的,@ HorseVoice要求提供Java 7版本,如下所示:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * https://stackoverflow.com/questions/32925049/check-if-a-list-is-a-value-in-a-hashmap
 *
 * @author surender.kumar
 */
public class CheckListValueInHashMapExists {

    public static final Map<String, List<String>> m = new HashMap<>();

    public static void main(String[] args) {
        System.out.println("Running main ...");
        initM();
        String gummi = "gummi";

        System.out.println("Do the list contains value gummi? " + checkValueExistsJava7());
    }

    private static boolean checkValueExistsJava7() {
        for (List<String> list : m.values()) {
            if (list.contains("gummi")) {
                return true;
            }
        }
        return false;
    }

    private static void initM() {
        List<String> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        list1.add("value1a");
        list1.add("value1b");
        list2.add("value2");
        list2.add("gummi");
        m.put("1", list1);
        m.put("2", list2);
    }
}

输出:

Running main ...
Do the list contains value gummi? true

答案 5 :(得分:0)

我认为Surender Kherwa的回答是合格的,但是我认为当您在集合中查找元素时,最好使用while循环而不是for,这是示例(对于Java 7):

String gummi = "gummi";
Map<String,List<String>> map = new HashMap<String,List<String>>() {
{

put("KEY1", new ArrayList<String>(){{
    add("check");
    add("if");
    add("a");
    add("list");
    add("is");
}});

put("KEY2", new ArrayList<String>(){{
    add("a");
    add("gummi");
    add("value");
    add("in");
    add("a");
}});

put("KEY3", new ArrayList<String>(){{
    add("HashMap");
    add("java");
    add("7");
    add("while");
    add("loop");
    add("version");
}});

}};

Iterator<Map.Entry<String, List<String>>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
  Map.Entry<String, List<String>> entry = iterator.next();
  if (entry.getValue().contains(gummi)) {
    System.out.println("Found in : " + entry.getKey());
    break;
  }
}

答案 6 :(得分:0)

如果该值为列表,则可以使用List的contains方法检查 列表具有必需的字符串。

public static void main(String args[]){
    public static final Map<String, List<String>> m = new HashMap<>();
    checkStringInMapOfLists("gummi",m);
}

以下方法迭代哈希图中的值,并检查哈希图中的任何列表是否包含所需的String

private boolean checkStringInMapOfLists(String input,Map<String, List<String>> m){
    for(List<String> list : m.values()){
        if(list.contains(input))
            return true;
    }
    return false;
}

答案 7 :(得分:0)

我已经使用Java 8检查了两种情况。下面的分析是针对最坏的情况。

方案1:地图包含1000000个键

似乎在这种情况下,java流API比循环慢。该地图包含1000000个键。 Streams花了107543400纳秒完成任务。循环耗时73688600纳秒。但是,并行流仅花费了51464500纳秒。

签出以下解决方案代码。

public static void main(String[] args) {
    try {
        App app = new App();
        String parameter = "invalid value";
        int numberOfKeys = 1000000;

        Map<String, List<String>> m = new HashMap<>();

        // adding values to map
        for (int i = 0; i < numberOfKeys ; i++) {
            m.put(i + "",
                    Arrays.asList(i * 10 + "", i * 11 + "", i * 12 + "", i * 13 + "", i * 14 + "", i * 15 + ""));
        }

        /** check time difference **/

        System.out.println("Loops");
        long begin = System.nanoTime();
        boolean b = app.containsValue_loops(m, parameter);
        System.out.println(System.nanoTime() - begin);
        System.out.println(b);

        System.out.println("\nJava 8 - stream");
        begin = System.nanoTime();
        boolean a = app.containsValue_java8(m, parameter);
        System.out.println(System.nanoTime() - begin);
        System.out.println(a);

        System.out.println("\nJava 8 - parallel stream");
        begin = System.nanoTime();
        boolean c = app.containsValue_java8_parallel(m, parameter);
        System.out.println(System.nanoTime() - begin);
        System.out.println(c);

    } catch (Exception e) {
        System.out.println(e);
    }
}


/** Checks parameter contains in the list using loops **/
public boolean containsValue_loops(Map<String, List<String>> m, String parameter) {
    for (List<String> list : m.values()) {
        if (list.contains(parameter)) {
            // return immediately if value contains in the list
            return true;
        }
    }
    return false;
}

/** Checks parameter contains in the list using streams **/
public boolean containsValue_java8(Map<String, List<String>> m, String parameter) {
    return m.values().stream().anyMatch(list -> list.contains(parameter));
}

/** Checks parameter contains in the list using parallel streams **/
public boolean containsValue_java8_parallel(Map<String, List<String>> m, String parameter) {
    return m.values().parallelStream().anyMatch(list -> list.contains(parameter));
}

这是输出:

Loops
73688600
false

Java 8 - stream
107543400
false

Java 8 - parallel stream
51464500
false

方案2:地图仅包含10个键

这是输出:

Loops
185000
false

Java 8 - stream
31721800
false

Java 8 - parallel stream
2987000
false

在这种情况下,for循环花费的时间少于流。它也比并行流更快。

因此,结论是我的建议是对较小的集合使用循环,如果有较大的集合,则使用并行流。

答案 8 :(得分:0)

迭代Map集合以检查每个映射值的inputString,以便您可以使用找到的匹配键来进一步使用。

    Map<String, List<String>> m = new HashMap<>();
    String searchStr="a";
    List<String> list1 = new ArrayList<>();
    list1.add("a");
    list1.add("b");
    m.put("1", list1);
    list1 = new ArrayList<>();
    list1.add("c");
    m.put("2", list1);
    list1 = new ArrayList<>();
    list1.add("a");
    list1.add("d");
    m.put("3", list1);

    for (Entry<String, List<String>> entry : m.entrySet()) {
        if (entry.getValue().contains(searchStr)) {
            System.out.println(searchStr+" found for map key="+entry.getKey());
        }
    }

答案 9 :(得分:0)

您必须问自己要浪费多少资源,以及该任务可以允许的运行时间是多少。因此,假设您需要一个简单的解决方案,那么该解决方案将变得非常简单。由于您使用的是哈希映射,因此键不会按任何顺序排序,因此您可以仅迭代键并查看列表是否包含值true,如果存在则中断循环。由于此解决方案过于简单,听起来像是一项家庭作业,因此我将把解决方案留给您。只是几行代码。从我的头顶看起来像:

for(String key:m.keyset()){
if(m.get(key).contains("gummi")) return true;
}
return false;

此外,如果键和列表上下文之间存在任何联系,则有许多找到解决方案的方法。一个正在使用人工智能以及回归/培训,因此您无需看列表就可以猜测列表的内容。

另一种解决方案是针对多核和并行处理的map-reduce。

看,您的问题太棒了,不同背景的不同人对问题的回答也不同。问题是,您尚未定义参数,例如所需的性能,要处理的数据量等,因此任何可行的方法都是正确的答案。

此外,在指针领域,您可以设计自己的数据结构来以最佳性能解决此问题。否则,您可以使用树木和其他杂技……但是您必须描述问题的框架。

https://plato.stanford.edu/entries/frame-problem/

在简单地将对象读取为字节数组的同时,您也可以拥有o(n)。

答案 10 :(得分:0)

这将获取映射列表中包含的任何值的键。 Java 7

public String getKeyForValue(String value) {
    for (String key : map.keySet())
        if (map.get(key).contains(value))
            return key;
    return null;
}

如果值包含在哈希映射Java 7列表内的任何位置,则返回true或false。

public boolean mapContains(String value) {
    for (String key : map.keySet())
        if (map.get(key).contains(value))
            return true;
    return false;
}

答案 11 :(得分:0)

这就是我所做的,只是将对象类型更改为您需要的任何类型

private static boolean isInListOfHash(Map<List<String>, ICommand> hashMap, String word) {
    for (List<String> list : hashMap.keySet()) {
        for (String string : list)
            if (string.equalsIgnoreCase(word))
                return true;
    }
    return false;
}

答案 12 :(得分:-1)

hashMap是键值存储,当您想将值搜索为值时速度很慢,因此首先将您的地图标准化,例如将其交换为键和值

Map<String, String> searchMap = m.entrySet().stream()
                .flatMap(entry -> entry.getValue().stream().map(etn -> new AbstractMap.SimpleEntry<>(etn, entry.getKey())))
                .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));

和类似这样的搜索值

String mkey = searchMap.get("gummi");

现在mkey是原始地图键。 if null在原始地图中的任何值中都不存在,并且如果key不为null,您可以像这样访问创建列表

List<String> mValue = m.get(mkey);

答案 13 :(得分:-1)

如果要检查Map的任何值内是否存在对象。使用Java-8及更高版本中涉及Stream的方法,您可以使用flatMap并收集toSet在扁平化集合上执行高效contains的情况:

boolean presentInAnyValue = m.values().stream()
        .flatMap(Collection::stream)
        .collect(Collectors.toSet())
        .contains("gummi");

此代码的Java-7转换如下:

Set<String> set = new HashSet<>();
for (List<String> strings : m.values()) {
    set.addAll(strings);
}
boolean presentInAnyValue = set.contains("gummi");