计算字母数字字符的出现次数并以图形方式打印

时间:2013-09-12 14:21:19

标签: java string

我有一个字符串,我想计算所有字母和数字的出现次数,并希望创建一个图形,以便我可以用图形方式查看事件。

例如:

String sentence = "ABC ABC ABC 123"

A (3) * * *
B (3) * * *
C (3) * * *
D
.
.

我的思维方式:

  1. 计算字符串中的所有数字和字母
  2. 打印所有星号乘以此数字(遗憾的是我无法将字符串与Java中的int相乘)
  3. 我认为有两种计算角色的方法。我可以使用charAt()方法或toCharArray()并循环遍历字符串或数组并计算字母数。

    例如:

    aCounter = 0;
    bCounter = 0;
    char ch = sentence.charAt(i);
    
    for (i = 0; i < sentence.length(); ++i) {
        if (ch == 'a') {
            aCounter++;
        }
        if (ch == 'b') {
            bCounter++;
        }
    }
    

    但是,这种方法存在多个问题:

    • 我需要制作很多反制变量 - aCounterzCounter0counter9counter
    • 我必须制作另一个for循环来打印星号!

    我不是在这里要求一个固定的答案,我只是在寻找一些好的方向,因为我被卡住了。

12 个答案:

答案 0 :(得分:8)

无需为此制作HashTable/HashMap/HashSet

您知道提前跟踪了哪些字符,因此您可以使用数组。

  

我想计算所有字母和数字的出现次数

创建一个您将跟踪的字符串,然后初始化一个数组。

String sentence = "ABC ABC ABC 123";

//Make a map of all the characters you want to track.
String indexes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

//Initialize an array to the size of the possible matches.
int[] count = new int[indexes.length()];

//Loop through the sentence looking for matches.
for (int i = 0; i < sentence.length(); i++) {
    //This will get the index in the array, if it's a character we are tracking
    int index = indexes.indexOf(sentence.charAt(i));

    //If it's not a character we are tracking, indexOf returns -1, so skip those.
    if (index < 0)
        continue;

    count[index]++;
}

然后你可以用它打印出来:

for (int i = 0; i < count.length; i++) {
    if (count[i] < 1)
        continue;

    System.out.println(String.format("%s (%d) %s",
            indexes.charAt(i),
            count[i],
            //This little bit of magic creates a string of nul bytes, then replaces it with asterisks.
            new String(new char[count[i]]).replace('\0', '*')));
}

如果您对new String(new char[count[i]]).replace('\0', '*'))位不熟悉,则可以在尝试输出之前使用StringBuilder构建星号String。您可以在下面看到 @mike 的示例作为一个很好的示例。

输出

1 (1) *
2 (1) *
3 (1) *
A (3) ***
B (3) ***
C (3) ***

考虑

在决定如何解决此问题时,需要考虑以下事项。

  • 您是否始终知道需要提前跟踪哪些字符,或者有时您想跟踪任何字符?在后一种情况下,阵列不适合您;您需要使用像TreeMap或HashMap这样的高级数据结构。
  • 您是否总是计算特定char s的出现次数,而不是String s?如果你必须修改它来计算String s,那么使用String indexes地图技巧也不会对你有效。
  • 您是否正在学习课程中的特定数据结构?通常会将这样的问题分配给学生,以了解如何应用特定概念。建议 @kyle ,您应该尝试使用您在课堂上学习或了解的数据结构。 有时候使用你尚未学到的结构可能会让你陷入困境,或者至少降低成绩。

答案 1 :(得分:2)

以下是一些可以帮助您入门的提示:

  1. 不要为每个计数器使用单独的变量。使用数组(或某些集合类型......如果你已经被教过......)。

  2. 您可以将字符用作数组索引。

  3. 在开始打印任何内容之前累积所有计数。

答案 2 :(得分:2)

您可以使用另一种方法,而不是循环一次计算金额,再循环第二次打印星号,您可以使用另一种方法:

Map<Character,String> results = new HashMap<Character, String>();

然后,每次迭代时,检查地图是否包含角色的数据,如果没有,则初始化它。在伪代码中:

If the map contains data for the key
    Obtain the data for the character
    append a new asterisk
Else
    Create a String with an asterisk
    Append an asterisk
    Put the String with the character as key

如果你需要数量的星号作为数字,你总是可以获得String的大小(假设你没有放任何空格)。


更新

作为一项改进,考虑到我与@crush分享的评论,两个调整可以改善逻辑:

  • StringBuilder而不是String避免不必要的文字创作。
  • TreeMap代替HashMap它会为地图提供正确的顺序,允许对其内容进行分类打印。

如果有足够的空间(和知识)来证明其使用的合理性,那就取决于OP增加这些额外的东西。

答案 3 :(得分:2)

这是一种使用StringReader和Map的OOP方法。我用了TreeMap 将输出排序。

public class StringHistogram
{
  public static void main(String[] args) throws IOException
  {
    Scanner sc = new Scanner(System.in);
    System.out.print("Please insert string: ");
    String s = sc.nextLine();
    sc.close();
    System.out.println(s);

    StringReader r = new StringReader(s);

    Map<Character, Integer> histogram = new TreeMap<Character, Integer>();
    int c;
    while ((c = r.read()) != -1) {
      Integer count = histogram.get((char) c);
      if (count == null)
        count = 0;
      histogram.put((char) c, count + 1);
    }
    r.close();
    for (Entry<Character, Integer> entry : histogram.entrySet())
      System.out.println(entry.getKey() + " (" + entry.getValue()
          + ") " + createAsterisk(entry.getValue()));
  }

  private static String createAsterisk(int number) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < number; i++)
      sb.append("*");
    return sb.toString();
  }
}

答案 4 :(得分:1)

创建一个哈希表并遍历字符串,每次将当前char添加到哈希表

     String str = "abc abc abc 123";
     Hashtable numbers = new Hashtable();
     int size = str.length();
     for(int i = 0 ; i< size ; i++)
     {
         char curr = str.charAt(i);
         if(numbers.contains(curr) == false)
         {
             numbers.put(curr, 1);
         }
         else
         {
             numbers.put(curr, ((int)numbers.get(curr)) + 1);
         }
     }

     Enumeration names = numbers.keys();
     char c;

     while(names.hasMoreElements()) {
        c = (char) names.nextElement();
        System.out.println(c + ": " +
        numbers.get(c));
     }

答案 5 :(得分:1)

使用数组存储计数器。您可以直接使用char作为数组索引,因此您不需要复杂的逻辑。

要打印给定数量的星号,for循环是最简单的方法。

答案 6 :(得分:1)

由于您是新手,并且还没有解决方案(每个人都在哪里开始),正确的答案是使用您在课堂上学习的数据结构。

如果您正在学习地图

  • TreeMap排序但键的自然顺序(很适合打印)
  • HashMap没有非常可预测的排序

如果您正在学习数组,那么此线程中有很多例子。暗恋的反应

答案 7 :(得分:0)

将它分为两​​个方法 - 一个用于给定一个char和一个String来创建一个String“row”,另一个用于为36个字母数字字符中的每一个调用第一个方法。

public static String alphNum = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

    public static String count(char c, String str) {
        String stringToReturn = Character.toString(c);
        for(char ch : str.toCharArray()) {
            if (ch == c) {
                stringToReturn += " *";
            }
        }
        return stringToReturn;
    }

    public static void countAndPrintAlphNum(String str) {
        String stringToTest = str.toUpperCase();
        Set<String> rows = new HashSet<String>();
        char[] alphNumArray = alphNum.toCharArray();
        for(char c : alphNumArray) {
            rows.add(count(c, stringToTest));
        }
        for(String row : rows) {
            System.out.println(row);
        }

    }

    public static void main(String[] args) {
        countAndPrintAlphNum("Hi There 123!");
    }

注意:如果要确保以字母 - 数字顺序(首先是数字)打印行,请使用TreeSet而不是行的HashSet。

答案 8 :(得分:0)

因为,我们生活在云计算和并行时代。这是另一种方法。

public class DistributedHistogram
{
  private static final int PORT = 1337;
  private static final String LOOPBACK = "127.0.13.37";

  public static final byte[] DATA = new byte[] {(byte) 0xFF, (byte) 0xFF};
  public static final byte[] STOP = new byte[] {(byte) 0xDE, (byte) 0xAD};

  public static void main(String[] args) throws IOException, InterruptedException
  {
    ExecutorService se = Executors.newSingleThreadExecutor();
    se.submit(new Server(PORT, 16));

    System.out.print("Please insert string: ");
    Scanner s = new Scanner(System.in);
    String input = s.nextLine();
    s.close();
    System.out.println(input);

    ExecutorService ce = Executors.newFixedThreadPool(16);
    List<Future<Void>> futures = new ArrayList<Future<Void>>();
    for (char c : input.toCharArray())
      futures.add(ce.submit(new Client(new Character[]{c}, DATA, LOOPBACK, PORT)));

    /* wait for the clients to complete before we send stop to server */
    for (Future<Void> f : futures)
    {
      try
      {
        @SuppressWarnings ("unused")
        Void v = f.get();
      }
      catch (ExecutionException e)
      {
        //...
      }
    }
    ce.submit(new StopClient(LOOPBACK, PORT)); // sends stop signal

    ce.shutdown();
    se.shutdown();
  }
}

class Client implements Callable<Void>
{
  private final Character[] chars;
  private final String ip;
  private final int port;
  private final byte[] type;

  public Client(Character[] chars, byte[] type, String ip, int port)
  {
    this.chars = chars;
    this.type = type;
    this.ip = ip;
    this.port = port;
  }

  @Override
  public Void call() throws Exception
  {
    Socket s = new Socket(ip, port);
    DataOutputStream out = new DataOutputStream(s.getOutputStream());
    for (Character c : chars) {
      out.write(type);
      out.writeChar(c);
    }
    out.flush();
    out.close();
    s.close();
    return null;
  }
}

class StopClient extends Client {

  public StopClient(String ip, int port)
  {
    super(new Character[]{' '}, DistributedHistogram.STOP, ip, port);
  }
}

class Server implements Callable<Void>
{
  private final int port;
  private ServerSocket ss;
  private final ExecutorService e;

  private final ConcurrentHistogram ch = new ConcurrentHistogram();
  private final AtomicInteger client = new AtomicInteger();

  private AtomicBoolean quit = new AtomicBoolean(false);

  public Server(int port, int clients)
  {
    this.port = port;
    this.e = Executors.newFixedThreadPool(clients);
  }

  public ConcurrentHistogram getHistogram() { return ch; }

  public void stop()
  {
    quit.set(true);
    e.submit(new Callable<Void>()
    {
      @Override
      public Void call() throws Exception
      {
        Thread.sleep(250);
        ss.close();
        return null;
      }
    });
  }

  @Override
  public Void call() throws Exception
  {
    ss = new ServerSocket(port);
    while (!quit.get() && !ss.isClosed())
    {
      try
      {
        e.submit(new ClientHandler(client.getAndIncrement(), ss.accept(), this));
      }
      catch (SocketException se)
      { continue; }
    }
    e.shutdown();
    System.out.println(ch.toString());
    while (!e.isTerminated()) { /* wait */ }
    return null;
  }
}

class ConcurrentHistogram
{
  private final ConcurrentMap<Character, AtomicInteger> histogram = new ConcurrentHashMap<Character, AtomicInteger>();
  private static final String HISTOGRAM_CHAR = "*";

  public ConcurrentMap<Character, AtomicInteger> getHistogram() { return histogram; }

  private String createAsterisk(int number)
  {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < number; i++)
      sb.append(HISTOGRAM_CHAR);
    return sb.toString();
  }

  @Override
  public String toString()
  {
    StringBuilder sb = new StringBuilder();
    List<Entry<Character, AtomicInteger>> data = new ArrayList<Entry<Character, AtomicInteger>>(histogram.entrySet());
    Collections.sort(data, new Comparator<Entry<Character, AtomicInteger>>()
    {
      @Override
      public int compare(Entry<Character, AtomicInteger> o1, Entry<Character, AtomicInteger> o2)
      {
        return o1.getKey().compareTo(o2.getKey());
      }
    });
    for (Entry<Character, AtomicInteger> entry : data)
    {
      int value = entry.getValue().get();
      sb.append(entry.getKey() + " " + String.format("%4s", "(" + value + ")") + " " + createAsterisk(value) + "\n");
    }
    return sb.toString();
  }

  public void addChar(Character c)
  {
    AtomicInteger value = histogram.get(c);
    if (value == null)
    {
      histogram.putIfAbsent(c, new AtomicInteger());
      value = histogram.get(c);
    }
    value.incrementAndGet();
  }
}

class ClientHandler implements Callable<Void>
{
  @SuppressWarnings ("unused")
  private final int client;
  private final Socket s;

  private final Server server;

  public ClientHandler(int client, Socket s, Server server)
  {
    this.client = client;
    this.s = s;
    this.server = server;
  }

  @Override
  public Void call() throws Exception
  {
    DataInputStream in = new DataInputStream(s.getInputStream());
    int c;
    int i = 0;
    byte[] bytes = new byte[2];
    while ((c = in.read()) != -1)
    {
      if (i < 2)
      { bytes[i++] = ((byte) c); }
      else if (Arrays.equals(bytes, DistributedHistogram.DATA))
      {
        i = 0;
        char ch = (char) (((c & 0x00FF) << 8) + (in.read() & 0x00FF));
        server.getHistogram().addChar(ch);
      }
      else if (Arrays.equals(bytes, DistributedHistogram.STOP))
      {
        i = 0;
        server.stop();
      }
      else
      { i = 0; }
    }
    in.close();
    s.close();
    return null;
  }
}

答案 9 :(得分:0)

这里是最后一个简约的 OOP答案。有效3线。它有效,因为字符可以解释为整数。

我有点担心不关闭扫描仪。但由于javadoc说System.in
is already open and ready to supply input data。我假设资源的关闭也由系统处理。

public class MinimalisticHistogram
{
  public static void main(String[] args)
  {
    int[] occurrences = new int[(int) Math.pow(2, 16)]; // 256 KB
    for (char c : new Scanner(System.in).nextLine().toCharArray()) occurrences[c]++;
    for (int i = 0; i < occurrences.length; i++) if (occurrences[i] != 0) System.out.println(String.format("%c %4s %s", i, "(" + occurrences[i] + ")", new String(new char[occurrences[i]]).replace('\0', '*')));
  }
}

答案 10 :(得分:0)

所以我使用了一个双循环来计算字符数。如果某个字符在其中一个数组中匹配,则计数将添加到第三个数组中。

for (int i = 0; i < zinArray.length; i++) {
    char c = zinArray[i];
    for (int j = 0; j < controleArray.length; j++) { 
        char d = controleArray[j];      
        if (c == d) {
        letterCount[j]++;
        break; 
        }
    }
}

答案 11 :(得分:0)

这就是我用StringBuffer

做算法的方法
rgb: 255 125 1
argb: 255 125 1 16

输出:

public class StringManipulation {


public static void main(String[] args) {
    int occurrences = 0;
    int count = 0;
    int firstLoc = 0;
    int lastLoc = 0;
    boolean countedMulti = false;

    StringBuffer sb = new StringBuffer();

    String a = new String("ABC ABC ABC 123");
    String lastStrChar = null;

    char tempChar = 'z';

    while (count <= a.length()-1) 
    {
        for (int scanner = 48; scanner <= 90; scanner++) 
        {

            if (a.charAt(count) == scanner) {
                tempChar = (char)scanner;

                for (int i = 0; i <= a.length() - 1; i++) 
                {

                    if (tempChar == a.charAt(i)) {

                        if (count == 0) 
                        {
                            occurrences += 1;

                            sb.append(tempChar);
                        }

                        if (count > 0) {
                            if (a.charAt(count) != a.charAt(count - 1)) 
                            {
                                occurrences += 1;
                            }
                        }
                    }

                    if (count == i + 1) 
                    {
                        sb.append(tempChar);
                        occurrences = 0;
                    }

                    if ((sb.length() - 1) >= 0) 
                    {
                        lastStrChar = sb.substring(sb.length() - 1);

                        firstLoc = sb.indexOf(sb.substring(sb.length() - 1));
                        lastLoc = sb.length() - 1;

                        if (count>0 && sb.lastIndexOf(lastStrChar,firstLoc) != sb.lastIndexOf(lastStrChar, lastLoc)) 
                        {
                            countedMulti = true; //if the index is different for the same character, a duplicate char is found
                        } 
                        else 
                        {                           
                            countedMulti = false;               
                        }
                    }
                }

                if (!countedMulti) 
                {
                    System.out.print(lastStrChar + " appeared " + occurrences + " times\n");    
                }
            }
        }

        count++;
    }
  }
}