首页 > 解决方案 > 无法将 Char 和 Int HashMap 转换为字符串

问题描述

我一直在试图弄清楚如何将所有元素(键和值)转换为字符串。例如,结果应该类似于“a2b3c4”。


import java.util.*;

class Main{
  public static String stringCompression(String s){

    s = s.toLowerCase();
    HashMap<Character,Integer> map = new HashMap<>();

  for (int i = 0; i < s.length(); i++){
    char c = s.charAt(i);
    if (map.containsKey(c)){
        map.put(c, map.get(c) + 1);
    }
    else{
      map.put(c, 1);
    }
  }

  StringBuilder sb = new StringBuilder(); 
  for (int i = 0; i < map.size(); i++){
    sb.append(map.get(i));
  }
  
  return sb.toString();

  }

  public static void main (String[] args){
    System.out.println(stringCompression("aabccccaaa"));
    System.out.println(stringCompression("abc"));
    System.out.println(stringCompression("AabBcCdDdDDeE"));
  }
}

标签: java

解决方案


tl;博士

map.get( i )是不正确的。您的键是Character对象,而不是int i循环中使用的对象。

调用Map#keySet并循环这些关键对象,而不是递增int i. 替换你for (int i = 0; i < map.size(); i++){for ( Character key : map.keySet() )

细节

顺便说一句,您使用“压缩”一词,但您所做的不是压缩。您正在计算每个字符的重复次数,而不是分别计算重复字符的每个系列。

您用于填充地图的代码是正确的。我们可以通过println查看地图的内容来看到这一点。对于输入"aabccccaaa",我们得到这张地图:map.toString(): {a=5, b=1, c=4}.

问题在于您使用StringBuilder. 你打电话map.get( i )。这意味着您要求映射到 0、1、2 等键的值。但是您没有使用整数作为密钥。您正在使用Character作为您的密钥类型。

相反,您应该在所有键的集合上循环。然后get为每个键做一个。您的StringBuilder代码应如下所示:

StringBuilder sb = new StringBuilder();
Set < Character > keys = map.keySet();
for ( Character key : keys )
{
    Integer count = map.get( key );
    sb.append( key ).append( count );
}

顺便说一句,您可以通过使用方法将您插入到地图中的单行调用中Map#merge。所以这:

    if (map.containsKey(c)){
        map.put(c, map.get(c) + 1);
    }
    else{
      map.put(c, 1);
    }

…变成这样:

map.merge( c , 1 , Integer :: sum );

Integer :: sum是一个方法参考。方法引用是表示该方法而不是调用该方法的对象。该方法将在执行其工作merge时调用该方法。sum

顺便说一句,您的行用一个新对象s = s.toLowerCase();替换了传递的参数对象。我不推荐这个。你放弃了原文,却一无所获。您已经丢弃了调试和记录所需的有价值的信息。相反,定义一个新变量:. 并且为了防止参数变量的这种重新分配,将参数声明标记为.StringStringStringString input = s.toLowerCase();final

完整的代码示例:

package work.basil.example;

import java.util.HashMap;
import java.util.Set;

public class RepeatCounter
{
    public static void main ( String[] args )
    {
        System.out.println( countCharacterOccurrence( "aabccccaaa" ) );
        System.out.println( countCharacterOccurrence( "abc" ) );
        System.out.println( countCharacterOccurrence( "AabBcCdDdDDeE" ) );
    }

    public static String countCharacterOccurrence ( final String s )
    {

        String input = s.toLowerCase();
        HashMap < Character, Integer > map = new HashMap <>();

        for ( int i = 0 ; i < input.length() ; i++ )
        {
            char c = input.charAt( i );
            map.merge( c , 1 , Integer :: sum );
        }
        // System.out.println( "map = " + map );

        StringBuilder sb = new StringBuilder();
        Set < Character > keys = map.keySet();
        for ( Character key : keys )
        {
            Integer count = map.get( key );
            sb.append( key ).append( count );
        }

        return sb.toString();
    }
}

跑的时候。

a5b1c4
a1b1c1
a2b2c2d5e2

您可能希望使用其他Map实现而不是HashMap. 该类HashMap不承诺其键的迭代顺序。

如果您希望键按排序顺序保存,请使用SortedMap/NavigableMap实现,例如TreeMap.

如果您希望键保持其原始插入顺序,请使用LinkedHashMap.

Map这是我用 Java 捆绑的实现制作的图表。

Java 11 中的地图实现表,比较它们的特性


顺便说一句,Java 中的char/Character类型已经过时,甚至无法表示Unicode中定义的 143,859 个字符的一半。

虽然您的代码可以处理“Hello World”的输入,但它会因输入“Hello world ️”而失败。

学习使用整数代码点编号。因此,您的 Map 将是Map < Integer , Integer >第一个Integer表示每个字符的代码点编号,第二个Integer是其出现次数的地方。

有关更多信息,请阅读:每个软件开发人员绝对、肯定必须了解 Unicode 和字符集的绝对最低要求(没有借口!)


推荐阅读