【问题标题】:How to insert multiple keys with the same value into a hash map in Java?如何将具有相同值的多个键插入Java中的哈希映射?
【发布时间】:2018-03-03 16:39:18
【问题描述】:

我正在 java 中进行以下编码挑战:

/**
     * 4. Given a word, compute the scrabble score for that word.
     * 
     * --Letter Values-- Letter Value A, E, I, O, U, L, N, R, S, T = 1; D, G = 2; B,
     * C, M, P = 3; F, H, V, W, Y = 4; K = 5; J, X = 8; Q, Z = 10; Examples
     * "cabbage" should be scored as worth 14 points:
     * 
     * 3 points for C, 1 point for A, twice 3 points for B, twice 2 points for G, 1
     * point for E And to total:
     * 
     * 3 + 2*1 + 2*3 + 2 + 1 = 3 + 2 + 6 + 3 = 5 + 9 = 14
     * 
     * @param string
     * @return
     */

我的想法是通过执行以下操作将所有这些字母插入哈希图中:

map.add({A,,E,I,O,U,L,N,R,S,T}, 1);

有没有办法在java中做到这一点?

【问题讨论】:

  • 当然。 map.put('A', 1); map.put('E', 1); 等。或者只是在键数组上使用循环。
  • 所以我不能在一个声明中做到这一点。
  • 是的,您可以,例如使用流 api 或 List.forEach。
  • 请注意,将集合作为键是非常低效的,因为需要经常进行哈希计算,这需要一遍又一遍地迭代整个键的集合。当然,您可以使用缓存其哈希值的自定义集合或忽略集合的哈希值而仅比较身份的 IdentityHashMaps 来解决此问题。
  • “我真正想要的是一个语句,我可以在其中将所有这些具有相同值的字母存储在 hash_map 中。”所以你应该在问题中提到这一点。如果您想要一个声明,请说出来。虽然这可能不是一件好事。

标签: java


【解决方案1】:

您在您的 cmets 中说过您希望能够在一个语句中添加所有这些条目。虽然 Java 不是一种在单个语句中执行此类操作的好语言,但如果您真的下定决心这样做,它是可以做到的。例如:

Map<Character, Integer> scores =
    Stream.of("AEIOULNRST=1","DG=2","BCMP=3","FHVWY=4" /* etc */ )
        .flatMap(line -> line.split("=")[0].chars().mapToObj(c -> new Pair<>((char)c, Integer.parseInt(line.split("=")[1]))))
        .collect(Collectors.toMap(Pair::getKey, Pair::getValue));

System.out.println("C = " + scores.get('C'));

输出:

C = 3

在上面的代码中,我首先构建了一个所有条目的流(作为 Pairs),并将它们收集到一个映射中。

注意:

我上面使用的 Pair 类来自javafx.util.Pair。但是,您可以轻松地使用 AbstractMap.SimpleEntry、您自己的 Pair 类或任何能够容纳两个对象的集合数据类型。


更好的方法

另一个想法是编写自己的辅助方法。该方法可以放入包含类似辅助方法的类中。这种方法会更惯用,更易于阅读,因此更易于维护。

public enum MapHelper {
; // Utility class for working with maps
public static <K,V> void multiKeyPut(Map<? super K,? super V> map, K[] keys, V value) {
for(K key : keys) {
    map.put(key, value);
}}}

然后你会这样使用它:

Map<Character, Integer> scores = new HashMap<>();
MapHelper.multiKeyPut(scores, new Character[]{'A','E','I','O','U','L','N','R','S','T'}, 1);
MapHelper.multiKeyPut(scores, new Character[]{'D','G'}, 2);
MapHelper.multiKeyPut(scores, new Character[]{'B','C','M','P'}, 3);
/* etc */

【讨论】:

  • @patzi 我用更惯用的方法更新了我的答案。再看看。
【解决方案2】:

取一个长度为 26 的数组,每个元素代表一个字母的分数。 所以,我们将有一个这样的数组:-

alphabetScore = [1,3,3,2,.....................];

现在,遍历单词,并继续将当前字母的分数添加到总分中。

【讨论】:

  • 我看不出这个答案与这个问题有什么关系,如何使用不同的键多次将相同的值插入到地图中......?
  • 因为这个问题可能是 X/Y 问题。我个人更喜欢这种方法而不是HashMap
  • 我认为这种方法更有效但更容易出错。我可能放错了一些号码;
  • 它不一定容易出错:只需在初始化和访问时使用 char 字面量即可。
【解决方案3】:

我认为将更多字符的列表存储为键(看看this question)和与该键对应的单个值并不是一个好主意,但是如果你真的需要它,你可能想尝试一下:

Map<ArrayList<Character>, Integer> map = new HashMap<>();
map.put(new ArrayList<Character>(Arrays.asList('A', 'E',...)), 1);
map.put(new ArrayList<Character>(Arrays.asList('D', 'G',...)), 2);

就个人而言,我建议使用 HashMap&lt;Integer, ArrayList&lt;Character&gt;&gt; - 键是一组字母的“值”(例如,对于包含字母 A、E 等的 ArrayList,键将是 1) ,作为对应于该整数键的值可以是ArrayList 存储字符(A,E,...)。您可以通过以下方式实现该结果:

Map<Integer, ArrayList<Character>> map = new HashMap<>();
map.put(1, new ArrayList<Character>(Arrays.asList('A', 'E',...)));
map.put(2, new ArrayList<Character>(Arrays.asList('D', 'G',...)));

【讨论】:

  • 在您的示例中,如何检索单个字母的字母分数?
  • 我真正想要的是一个语句,我可以在其中将所有这些具有相同值的字母存储在 hash_map 中。
  • for (Map.Entry, Integer> entry : map.entrySet()) { if (entry.getKey().contains('a')) { int value = entry .getValue();打破;}}
  • 请注意,将集合作为键是非常低效的,因为需要经常进行哈希计算,这需要一遍又一遍地迭代整个键的集合。当然,您可以使用缓存其哈希值的自定义集合或忽略集合的哈希值而仅比较身份的 IdentityHashMaps 来解决此问题。
  • @Zabuza 我知道这是个坏主意,我建议 OP 使用字母的“值”作为键,并且字母列表可以存储为相应整数键的值。我给了他一个可能性,他如何实现这一目标。
【解决方案4】:

Map 没有对多个键进行操作的方法,但您可以流式传输这些字符的列表并调用forEach

Map<Character, Integer> scores = new HashMap<>();
Stream.of('A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T')
      .forEach(c -> scores.put(c, 1));
Stream.of('D', 'G').forEach(c -> scores.put(c, 2));
// etc...

【讨论】:

  • forEach(scores::put) 理论上可能会导致并发问题。一般来说,您应该警惕具有副作用的流。相反,构建所有条目的流并将它们收集到地图中。
【解决方案5】:

一行:

Map<String, Integer> map = Stream.of( "A", "E", "I", "O", "U", "L", "N", "R", "S", "T" ).collect( Collectors.toMap( Function.identity(), o -> 1 ) );

或者如果你已经有一个字符串列表

Collection<String> chars = new ArrayList<>();
// Add to collection
Map<String, Integer> map = chars.stream().collect( Collectors.toMap( Function.identity(), o -> 1 ) );

您可以使用相同的方法添加具有相同值的其他键

map.addAll( Stream.of( "F", "H", "V", "W", "Y" ).collect( Collectors.toMap( FUnction.identity(), o -> 4 );

最终,最好使用辅助函数来提高可读性

private Map<String, Integer> mapScores( int score, String... letter ) {
    return Stream.of( letter ).collect( Collectors.toMap( Function.identity(), o -> score ) );
}

Map<String, Integer> map = new ConcurrentHashMap<>();
map.putAll( mapScores( 1, "A", "E", "I", "O", "U", "L", "N", "R", "S", "T" ) );
map.putAll( mapScores( 2, "D", "G" ) );
map.putAll( mapScores( 3, "B", "C", "M", "P" ) );
map.putAll( mapScores( 4, "F", "H", "V", "W", "Y" ) );
map.put( "K", 5 );
map.putAll( mapScores( 8, "J", "X" ) );
map.putAll( mapScores( 10, "Q", "Z" ) );

【讨论】:

    猜你喜欢
    • 2018-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-26
    • 2017-01-20
    • 2015-09-08
    • 1970-01-01
    • 2014-12-13
    相关资源
    最近更新 更多