【问题标题】:Update a List element based on a HashMap value/key根据 HashMap 值/键更新列表元素
【发布时间】:2021-05-22 06:16:04
【问题描述】:

我有 ArrayList:

List<String> wordsList = new ArrayList<>();
// [eu, quero, voltar, para, praia, e, comer, queijo]

还有 HashMap:

Map<String, String> wordsMap = new HashMap<>();
//{v.=voltar, c.=comer, q.=queijo., p.=praia}

我正在尝试做:如果列表元素等于地图值,则将列表元素替换为地图key。在此示例中,结果将是:

// [eu, quero, v., para, p., e, c., q.]

我试过的东西是

      for (String word : wordsList) {
         for (Map.Entry<String, String> entry : wordsMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (word.equals(value)) {
               newWordsList.add(key);
            } else {
               newWordsList.add(word);
            }
         }
      }
Result: [eu, eu, eu, eu, quero, quero, quero, quero, v., voltar, voltar, voltar, para, para, para, para, praia, praia, praia, p., e, e, e, e, comer, c., comer, comer, queijo, queijo, q., queijo]

有什么帮助吗??谢谢!

【问题讨论】:

    标签: java arraylist hashmap


    【解决方案1】:

    对我来说,第一步是创建一个使用值作为键并将键作为值的新映射。这比遍历旧地图并检查值要容易得多。

    Map<String, String> invertedWordsMap = wordsMap.entrySet().stream().collect(Collecotrs.toMap(Map.Entry::getValue), Map.Entry::getKey));
    //{voltar=v., comer=c., queijo=q.., praia=p.}
    

    然后我只需要检查地图中是否存在密钥

    for (int i = 0; i < wordsList.size(); i++) {
        String word = invertedWordsMap.get(wordsList.get(i));
        if (word != null) {
            wordsList.set(i, word);
        }
    }
    

    这是强制性的花式流答案。请记住,如果您使用流解决方案,旧列表将被替换而不是更改。

    wordsList = wordsList.stream().map(word -> invertedWordsMap.getOrDefault(word, word)).collect(Collectors.toList());
    

    【讨论】:

    • 没有外部依赖来获得与我的答案相同的效果...+1 没想到 :)
    • 非常好的和干净的解决方案!非常感谢!!我也尝试过使用流,但我有点迷路所以我放弃了嘿嘿。
    • 如果你开始使用流,它们可能会有点不知所措,但通过一些练习,它们真的很方便:)
    • @ArvindKumarAvinash 参数相同但结果不同。 getOrDefault(key, defaultValue) 基本上是这样做的:if (map.get(key) != null) { return map.get(key); } else { return defaultValue; }
    • @magicmn - 棒极了!我知道getOrDefault 是如何工作的,但不知何故我错过了以它的工作方式来解释它。
    【解决方案2】:

    您可以简单地迭代wordsMap.entrySet(),在wordsList 中找到entry#value 的索引,然后将索引处的wordsList 更新为entry#key

    演示:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    public class Main {
        public static void main(String[] args) {
            List<String> wordsList = new ArrayList<>(
                    List.of("eu", "quero", "voltar", "para", "praia", "e", "comer", "queijo."));
            Map<String, String> wordsMap = Map.of("v.", "voltar", "c.", "comer", "q.", "queijo.", "p.", "praia");
    
            for (Map.Entry<String, String> entry : wordsMap.entrySet()) {
                int index = wordsList.indexOf(entry.getValue());
                if (index != -1) {
                    wordsList.set(index, entry.getKey());
                }
            }
    
            System.out.println(wordsList);
        }
    }
    

    输出:

    [eu, quero, v., para, p., e, c., q.]
    

    注意: List#indexOf 返回此列表中指定元素第一次出现的索引,如果此列表不包含该元素,则返回 -1。因此,上面给出的解决方案中的逻辑检查-1,并且只有匹配值的第一次出现将被替换。如果您的列表中有重复元素,并且您希望替换所有匹配值的出现,则需要找到匹配值的所有索引并替换它们,如下所示:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;
    
    public class Main {
        public static void main(String[] args) {
            List<String> wordsList = new ArrayList<>(List.of("eu", "quero", "queijo.", "voltar", "queijo.", "para", "praia",
                    "e", "queijo.", "comer", "queijo."));
            Map<String, String> wordsMap = Map.of("v.", "voltar", "c.", "comer", "q.", "queijo.", "p.", "praia");
            
            for (Map.Entry<String, String> entry : wordsMap.entrySet()) {
                List<Integer> allIndices = allIndicesOf(wordsList, entry.getValue());
                for (int index : allIndices) {
                    wordsList.set(index, entry.getKey());
                }
            }
    
            System.out.println(wordsList);
        }
    
        static List<Integer> allIndicesOf(List<String> list, String str) {
            return IntStream.range(0, list.size())
                    .boxed()
                    .filter(i -> list.get(i).equals(str))
                    .collect(Collectors.toList());
        }
    }
    

    输出:

    [eu, quero, q., v., q., para, p., e, q., c., q.]
    

    【讨论】:

      【解决方案3】:

      我会使用 google HashBiMap 因为它可以提供同一地图的逆视图,即在Map&lt;K,V&gt; 中,您可以同时使用get(K) returns Vget(V) returns K

              // Form the words list
              List<String> wordsList = new ArrayList<String>();
              wordsList.add("eu");
              wordsList.add("quero");
              // etc adding all of the terms you mentioned
      
              // Form the keyset
              HashBiMap<String, String> wordsMap = HashBiMap.create();
              wordsMap.put("v", "voltar");
              wordsMap.put("c", "comer");
              // etc adding all the terms you mentioned
      
              List<String> wordsListOut = new ArrayList<String>();
      
              // Iterating through the wordsList
              for (int i = 0; i < wordsList.size(); i++) {
      
                  // Get the current element
                  String element = wordsList.get(i);
                  // Does it have an inverse pair?
                  String result = wordsMap.inverse().get(element);
      
                  // If it has an inverse pair, add the inverse key. Otherwise, add the element raw.
                  wordsListOut.add(result == null ? element : result);
      
              }
      
              // Outputs: [eu, quero, v, para, p, e, c, q]
              System.out.println(wordsListOut);
      

      HashBiMap 的依赖是 Google Guava:

      <dependency>
          <groupId>com.google.guava</groupId>
          <artifactId>guava</artifactId>
          <version>30.1-jre</version>
      </dependency>
      

      【讨论】:

      • 注意:与@Thibaut Ledent 的回答类似,将“q2,queijo”添加到地图会导致非法参数异常(重复值已经存在:queijo)
      【解决方案4】:

      给定列表和地图:

      List<String> wordsList = Arrays.asList("eu", "quero", "voltar", "para", "praia", "e", "comer", "queijo");
      Map<String, String> wordsMap = Map.of("v.", "voltar", "c.", "comer", "q.", "queijo", "p.", "praia");
      

      然后下面的代码返回你的结果(没有任何外部依赖):

      // If the list element is equal to map value, then replace the list element
      // by the map key.In this example, the result would be:
      
      wordsMap.values().stream()
          // If the list contains the map value
          .filter(wordsList::contains)
          .forEach(value -> {
              // Find the corresponding map key
              String mapKey = wordsMap.entrySet()
                  .stream()
                  .filter(entry -> Objects.equals(entry.getValue(), value))
                  .map(Map.Entry::getKey) // It could find several keys if you have the same value for different keys
                  .findFirst()
                  .orElseThrow(); // It should never happen as we are looping in the map values
      
              // Find the index and update the list with the map key
              int index = wordsList.indexOf(value);
              wordsList.set(index, mapKey);
          });
      
      System.out.println(wordsList);
      // [eu, quero, v., para, p., e, c., q.]
      

      【讨论】:

      • 很高兴它没有使用其他依赖项。我发现流不是很容易阅读,所以我个人不经常使用它们。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-18
      相关资源
      最近更新 更多