7
votes

Compter la survenue de caractères alphanumériques et les imprimer graphiquement

J'ai une chaîne et je veux compter la survenue de toutes les lettres et numéros et que vous souhaitez créer un graphique afin que je puisse voir l'occurrence graphiquement.

Donc, par exemple: xxx

ma façon de penser:

  1. compter tous les chiffres et les lettres de la chaîne
  2. Imprimez tous les astérisques fois ce numéro (malheureusement, je ne peux pas multiplier une chaîne avec un int in dans Java)

    Je pense qu'il y a deux façons de compter les personnages. Je peux utiliser l'utilisation de la méthode Charat () ou TOCHARARRAY () et boucle via la chaîne ou la matrice et compter les lettres.

    Par exemple: xxx

    Cependant, j'ai plusieurs problèmes avec cette approche:

    • J'aurais un pour faire beaucoup de variables de comptoir - acounter via zcounter plus 0counter via 9counter
    • Je devrais faire une autre boucle pour imprimer les astérisques!

      Je ne demande pas une réponse définie ici, je suis juste à la recherche de bonnes directions, car je suis coincé.


6 commentaires

Utilisez un HASHMAP, en utilisant les caractères comme touches de la carte. Ensuite, c'est une simple question de (en pseudo-code) carte [caractère] ++ .


Oh, tu veux le nombre de seventions de chaque personnage. Duh. Savait que cela semblait trop facile. Pas que ce n'est pas facile. Marc B a la bonne idée.


Vous pouvez utiliser une carte ou même un tableau, car vous savez combien de caractères + numéros sont dans l'alphabet.


Est-ce que case importe? Ou devrait-il être traité le même?


var charcant = 0 var c = null; pour (var i = 0; i


Je suggère d'utiliser un tableau de int [] plutôt que d'engendrer la surcharge d'un hashmap . Il serait intéressant de voir la performance de mon exemple par rapport à un exemple hashmap .


12 Réponses :


8
votes

Il n'y a pas besoin de faire un hashtable / hashmap / hashmet pour cela.

Vous savez quels caractères sont suivis à l'avance, donc vous peut utiliser un tableau.

Je veux compter la survenue de toutes les lettres et numéros

Créez une chaîne de caractères que vous suivez, puis initialisez un tableau. xxx

puis vous pouvez tous les imprimer avec ceci: xxx

Si vous n'êtes pas à l'aise avec la nouvelle chaîne (nouveau char [Nombre [i]]). Remplacez ('\ 0', '*')) Bit, alors vous pouvez utiliser un StringBuilder pour créer la chaîne d'astérisque avant d'essayer de le sortir. Vous pouvez voir @mike s selon l'exemple ci-dessous pour un bon exemple de cela.

sorties xxx

Considérations

Voici certaines choses à prendre en compte lorsqu'ils ont décidé comment résoudre ce problème.

  • Sachez-vous toujours quels caractères doivent être suivis à l'avance ou y aurez-vous des moments où vous souhaitez suivre tout personnage ? Dans ce dernier cas, un tableau ne fonctionnera pas pour vous; Vous auriez besoin d'utiliser une structure de données avancée comme un Treemap ou un hashmap.
  • Voulez-vous toujours compterez-vous toujours des occurrences de char S, par opposition à la chaîne S? Si vous devez modifier ceci pour compter String s puis à l'aide des index de la chaîne La carte ne va pas fonctionner pour vous non plus.
  • Apprenez-vous une structure de données spécifique dans votre cours pour le moment? Des problèmes généralement tels que ceux-ci sont attribués aux étudiants de comprendre comment appliquer un concept spécifique. AS @KYLE suggéré, vous devriez essayer d'utiliser la structure de données que vous apprenez ou que vous avez appris, dans votre classe. Parfois, utilisez des structures que vous n'avez pas encore apprises pour que vous puissiez vous mettre en difficulté, ni un grade inférieur au moins.


10 commentaires

J'ai ajouté une autre approche ... une tropillasse. Si j'ai le temps, je vais créer un troisième avec moins de lignes de code que possible.


Bien qu'il soit vrai que vous n'avez pas besoin de hashmap , il s'agit d'une structure de données adaptée à la tâche (bien, en réalité, une multiset est, mais nous n'avons pas celui-ci dans les bibliothèques standard Java) . Votre approche fonctionne pour la plupart des intrants bien, mais si je vis à vivre dans un pays qui a des personnages spéciaux comme "ěščřžýáé"? Et si j'oublie certains ("ůůňťď")? En outre, invoquer indexofof () sur chaque itération fonctionne, mais je suis curieux de ses performances avec des chaînes d'entrée LOOOOOOONG. Tous, alors que cela fonctionne, je ne dirais pas que c'est un moyen d'aller avec les approches modernes Java existant. Ce sont les années 1990 qui appelle à nouveau


@Slanec indexof est appelé sur la carte des caractères suivis et non sur la chaîne d'entrée elle-même. En outre, lisez ma section Considérations et vous verrez que les autres points que vous avez faits sont déjà dans ma réponse.


@crush je me sens mal et je suis désolé. Je dois admettre honteusement que je n'ai pas lu cette section. Cela raconte en effet toute l'histoire. Et oui, je suis au courant de l'index de () d'utilisation et je serais toujours inquiet. Il est toujours linéaire sondage et à petite échelle, ce n'est rien, si le tableau était plus long et que nous avions beaucoup d'informations, cela pourrait être notable. C'est une bonne approche à des fins éducatives, cependant, oui.


@Slanec pas besoin d'être honteux! Je le fais tout le temps ;)


Je dois contrer votre première considération. Un tableau fonctionnera toujours si Char S est considéré, car ils ont une taille fixe de 2 octets.


@mike Cela ne fonctionnerait pas parce que vous ne savez pas à quel point pour faire le tableau initialement. tout signifie que vous ne savez pas ce que tous les caractères que vous suivez, vous devez donc suivre n'importe quel personnage rencontré, vous devez donc allouer la matrice à une taille énorme pouvant aller gaspiller. , ou vous auriez besoin de réaffecter le tableau car il grandit - d'une bonne affaire d'utiliser une structure de données comme un hashmap .


Je l'ai fait ici: Stackoverflow.com/a/18787187/1809463 depuis qu'un caractère a une taille fixe de 16 bits, il y a 2 ^ 16 = 65536 Affectations possibles pour un Char .


@ Mike Droite - et la plupart de ces éléments sont gaspillés car 90% d'entre eux ne seront pas présents dans la chaîne d'entrée.


@crush il ne nécessiterait que 256kb de mémoire. Pas une grosse affaire sur les machines modernes. Mais oui, il restait encore beaucoup d'INT inutilisé à gauche.



1
votes

Créez une haquetable et passez par la chaîne, ajoutez chaque fois le caractère actuel de la haquetable xxx


3 commentaires

C'est une approche propre. N'oubliez pas d'aborder l'impression de la sortie (la question des astérisques) avec votre réponse!


@crush a ajouté que. Nice nom BTW


hashtable et énumération - quelle année est-ce? :) (le code moderne utiliserait hashmap et itérateur )



1
votes

Utilisez un tableau pour stocker les comptoirs. Vous pouvez utiliser un caractère directement en tant qu'index de tableau, de sorte que vous n'avez pas besoin de logique complexe.

Imprimer un nombre donné d'astérisques, une bouclette est la solution la plus simple.


6 commentaires

Le moyen le plus simple serait ce que @crush a fait nouvelle chaîne (nouveau char [Nombre [I]]). Remplacer ('\ 0', '*'))


Ce qui est "plus facile" est discutable - créer une matrice pleine de caractères nul, créant une chaîne de ce tableau et créer une autre chaîne dans laquelle chaque caractère nul est remplacé par un astérisque n'est pas trivial et inefficace. C'est un tour soigné cependant.


@Joni plus efficace utiliserait un StringBuilder, mais vous vous retrouvez avec au moins 2-3 autres lignes de code en fonction de la façon dont vous l'avez écrites. La concaténation de la chaîne dans A pour la boucle sera remarquablement pire, cependant. Je n'ai pas votre commentaire à ce sujet en train d'être non trivial . Cela me semble assez trivial.


@crush j'ai utilisé un stringbuilder dans la réponse que j'ai posté. ... Mais j'ai toujours eu une fable pour un one-liners: D ... Je pense qu'avec non trivial, il voulait dire qu'il est un type de piratage et non la première approche qui vient à l'esprit.


Si vous souhaitez imprimer un nombre donné d'astérisques, la première chose qui vous vient à l'esprit est une boucle qui les imprime un par un. Construire une chaîne est un pas en avant dans l'échelle d'abstraction ...


D'accord. Je n'ai pas assimilé non trivial avec ça, mais je comprends ce que vous voulez dire maintenant. StringBuilder est peut-être la meilleure solution pour l'impression n astérisques, comme @Mike le fait dans son exemple.



2
votes

Voici quelques astuces pour vous aider à démarrer:

  1. n'utilise pas une variable séparée pour chaque compteur. Utilisez un tableau (ou un type de collecte ... Si vous avez appris à ce sujet ...).

  2. Vous pouvez utiliser un caractère comme indice de tableau.

  3. accumuler tous les comptes avant de commencer à imprimer quelque chose.


1 commentaires

@Mike Parfois, le code fait une meilleure explication. =) C'est une belle sommation de ma mise en œuvre ci-dessous, cependant. C'est abstrait! +1



2
votes

au lieu de boucler une fois pour calculer la quantité et en boucle une seconde fois pour imprimer les astérisques, vous pouvez utiliser une autre approche: xxx

puis, chaque fois que vous iTeriez, vous vérifiez si votre La carte contient des données pour le caractère et, si ce n'est pas le cas, vous l'initialisez. En pseudocode: xxx

Si vous avez besoin de la quantité d'astérisques en tant que nombre, vous pouvez toujours obtenir la taille de ce chaîne (supposant que vous ne donez pas 'T mettre des espaces blanchisseurs).

mise à jour

comme une amélioration, en tenant compte des commentaires que j'ai partagés avec @crush, deux modifications peuvent améliorer la logique:

  • stringbuilder au lieu de chaîne : éviter la création inutile de littéraux.
  • Treemap au lieu de hashmap : Il donnerait la commande appropriée à la carte, permettant une impression triée de son contenu.

    C'est à la question d'ajouter cette affaire supplémentaire, s'il y a une place (et une connaissance) suffisamment pour justifier leur utilisation.


6 commentaires

N'oubliez pas de mettre à jour le nombre d'occurrences dans la chaîne aussi. N'oubliez pas que le format est a (3) *** vous devez également mettre à jour le compte. En fin de compte, vous devez toujours itérer sur la carte pour afficher chaque chaîne .


@crush Le compte est la taille de la chaîne stockée. Et en effet, vous devez itération sur la carte, mais vous avez toutes les informations là-bas. C'est une seule itération d'afficher les résultats à la fin.


Oh, j'ai manqué que vous étiez simplement en train de stocker une chaîne d'astérisques. Donc, à la fin, vous auriez quelque chose comme string.format ("% s (% d)% s", entrée.getkey (), entrée.gevalue (). Longueur (), entrée.gevalue (), entrée.gevalue () );


@crush, par exemple, oui, si l'OP connaît environ Format de chaîne . Sinon, une simple concaténation fonctionne aussi :)


Je pense que votre réponse n'atteignait pas l'attention qu'elle mérite. Par exemple, ma réponse nécessiterait trois boucles, sinon pour le string.replace () entreprise (qui est techniquement en boucle en interne). Cette approche ne nécessitera que deux boucles. Je préférerais voir l'utilisation d'un Treemap cependant, je pense. Retour à mon array exemple, cependant, un tableau de chaîne pourrait accomplir le même résultat, mais les concatenations seraient désagréables car elles créeraient une nouvelle chaîne immuable sur chaque boucler.


@crush et moi avons évoqué le vôtre pour cette utilisation intelligente d'index;). En effet, Treemap serait un bon diape afin d'imprimer les valeurs avec la commande appropriée, étant donné que le caractère est livré avec un comparète implémentation. Je dirais que je dirais que l'approche string , car je ne suis pas tout à fait sûr que l'opération connaît sur stringbuilder . Au début, j'avais utilisé des constructeurs au lieu des cordes crus mais sont allés pour une approche plus simple afin de manifester un certain degré de simplicité, Bot Ces deux points sont une bonne mise à jour.



0
votes

Divisez-le en deux méthodes b> - une pour créer une chaîne "rangée" donnée un char et une chaîne, et un pour appeler la première méthode pour chacun des 36 caractères alphanumériques.

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!");
    }


1 commentaires

@crush c'est vrai, oui. En «assurez-vous», je pensais à la programmation de manière défensive (si la chaîne d'alpnum n'est pas dans l'ordre). Bien sûr, d'une autre part, avoir peut-être que la dernière fois est souhaitée et que nous allions donc utiliser un hashset.



2
votes

Voici une approche d'OOP, qui utilise Stringreader code> et une carte. J'ai utilisé Treemap code> avoir la sortie triée.

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();
  }
}


0 commentaires

1
votes

Depuis que vous êtes nouveau à cela et que vous n'avez pas déjà la solution (qui est l'endroit où tout le monde commence), la réponse droite est d'utiliser la structure de données que vous apprenez en classe.

Si vous apprenez des cartes

  • TREEMAP Tries mais Natural Order of the Key (Nice pour l'impression)
  • hashmap n'a pas de commande très prévisible

    Si vous apprenez des tableaux, il existe de grands exemples dans ce fil déjà ex. Réponse du béguin


1 commentaires

Excellent point. Cela ne devrait tout simplement pas être négligé. Comme il s'agit d'une mission de devoirs, il est important d'appliquer ce que vous apprenez en classe au problème.



0
votes

Depuis, nous vivons en période d'informatique en nuage et de parallélisme. Voici une autre approche.

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;
  }
}


2 commentaires

Hahah. Ce serait une bonne approche si comptant les occurrences de caractères dans la Bible.


: D pris mon temps, pour obtenir le serveur de quitter après le dernier message est envoyé. En attente avec f.get () seul, n'a pas aidé, j'ai dû ajouter un délai avant de fermer la prise de serveur ... BTW J'ai ajouté une troisième et dernière solution. C'est aussi court que possible. Au moins je le pense.



0
votes

ici, une dernière réponse minimaliste non forte> oop. Avec efficacement 3 lignes. Cela fonctionne, car les caractères peuvent être interprétés comme des entiers.

J'étais un peu inquiet de ne pas fermer le scanner. Mais puisque le javadoc dit system.in code>
est déjà ouvert et prêt à fournir des données d'entrée code>. Je suppose que la fermeture de la ressource est également traitée par le système.

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', '*')));
  }
}


1 commentaires

Vous avez triché en cordant un tas d'énoncés sur cette ligne finale;)



0
votes

Alors j'ai utilisé un double pour boucle le comptage des personnages. Si un caractère a été adapté à l'un des matrices, le nombre a été ajouté dans le troisième tableau.

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; 
        }
    }
}


0 commentaires

0
votes

Voici comment j'ai fait l'algorithme avec Stressbuffer

A appeared 3 times
B appeared 3 times
C appeared 3 times
1 appeared 1 times
2 appeared 1 times
3 appeared 1 times


0 commentaires