首页 > 解决方案 > 如何遍历地图并返回所有匹配的地图?

问题描述

我为某人制作了各种方法来添加一个键,该键然后包含来自另一个创建的对象的各种值。

然后我需要允许用户使用方法名称进行搜索,然后返回所有匹配他们搜索的人。

     public Set findPerson(String aTrade)
     {
        Set<String> suitablePeople = new HashSet<>();
     
        for (String test : this.contractors.keySet())
        {
           System.out.println(contractors.get(test));
           if (contractors.containsValue(aTrade))
           {
              suitablePeople.add(test);
           }
        }
        
        return suitablePeople;
     }

我知道这段代码是错误的,但我只是不确定如何简单地通过并找到一个值并返回所有在一个值范围内具有该值的人。例如,他们的年龄、工作、地点。

标签: java

解决方案


一些假设,因为您的问题相当不清楚:

  • contractors是一个Map<String, ContractorData>字段。可能 ContractorData 是某种集合类型(例如MyList<Contractor>),或者命名不同。String 代表一个用户名
  • aTradeContractorData是一个字符串,您想在地图中存储的各种对象中搜索它。然后,您想要返回映射到包含匹配交易的对象的所有用户名字符串的集合。ContractorDataaTrade
  • 无论ContractorData可能是什么,它都有一个方法,如果承包商数据被认为是匹配的,则该方法containsValue(String)会返回。true(如果那是伪代码并且它实际上是List<String>,那么就.contains()可以完成这项工作。如果这是其他东西,您将不得不在您的问题中详细说明。

然后,没有可用的快速搜索;地图允许您快速搜索它们的键(而不是键的任何特定属性,而不是它们的值或它们值的任何特定属性)。因此,任何搜索本质上都意味着您遍历所有键/值映射并单独检查每个映射是否匹配。如果这不是可接受的性能成本,则必须制作另一个映射,将这个属性映射到某个东西。这可能必须是多图,并且要复杂得多。

性能成本并不重要

好的,那么,只是.. 循环,但请注意,它.entrySet()为您提供了键(如果匹配,您将需要它)和值(您需要检查它是否匹配),所以这要简单得多。

var out = new ArrayList<String>();
for (var e : contracts.entrySet()) {
    if (e.getValue().containsValue(aTrade)) out.add(e.getKey());
}

return out;

或者如果您更喜欢流语法:

return contracts.entrySet().stream()
    .filter(e -> e.getValue().containsValue(aTrade))
    .map(Map.Entry::getKey)
    .toList();

性能成本很重要

然后它变得复杂。您需要一个“包裹”至少两个地图的单个对象,并且您需要这个,因为您希望这些地图永远不会“不同步”。你需要一张地图来处理你想要的每件事find

因此,如果你想要 agetTradesForUser(String username)和 a findAllUsersWithTrade(String aTrade),你需要两张地图;一种将用户映射到交易,一种将交易映射到用户。此外,您需要多映射的概念:将一个键映射到(可能)多个值的映射。

您可以使用 guava 的 MultiMaps(guava 是一个第三方库,其中包含一些有用的东西,例如 multimaps),或者您自己滚动,这很简单:

给定:

class ContractData {
    private List<String> trades;

    public boolean containsValue(String trade) {
        return trades.contains(trade);
    }

    public List<String> getTrades() {
        return trades;
    }
}

然后:

class TradesStore {
  Map<String, ContractData> usersToTrades = new HashMap<>();
  Map<String, List<String>> tradesToUsers = new HashMap<>();

  public void put(String username, ContractData contract) {
    usersToTrades.put(username, contract);
    for (String trade : contract.getTrades()) {
      tradesToUsers.computeIfAbsent(username, k -> new ArrayList<>()).add(username);
    }
  }

  public Collection<String> getUsersForTrade(String trade) {
    return tradesToUsers.getOrDefault(trade, List.of());
  }
}

getOrDefault如果交易不在地图中,该方法允许您指定默认值。因此,如果您要求“让我拥有所有交易的用户 [SOME_VALUE_NOBODY_IS_TRADING]”,这将返回一个空列表(List.of()给您一个空列表),这是正确的答案(null 将是错误的 - 有一个答案,它是:没人。null 是指:未知/不相关,因此这里不正确)。

computeIfAbsent方法只是为您获取与键关联的值,但是,如果还没有这样的键/值映射,您还可以为其提供生成它所需的代码。在这里,我们传递了一个函数k -> new ArrayList<>()(我们不需要做初始值)。

因此,computeIfAbsent结合getOrDefault起来使多图的概念易于编写。


推荐阅读