web-dev-qa-db-fra.com

Comment fonctionne uniq?

Ne confondez pas cette question avec un doublon de "quelle est la différence n/b sort -u et sort | uniq"

Il s'agit essentiellement d'un programme de comptage de mots

La confusion suscitée par la commande suivante est la raison de poser cette question:

    root@sanctum:~/datascience# cat data 
    this is a file that is supposed to be a file

cela donne une sortie incorrecte:

root@sanctum:~/datascience# cat data | sed 's/ /\n/g' | uniq -c
      1 this
      1 is
      1 a
      1 file
      1 that
      1 is
      1 supposed
      1 to
      1 be
      1 a
      1 file

Le fait de canaliser la sortie pour trier puis vers uniq donne la réponse parfaite

root@sanctum:~/datascience# cat data | sed 's/ /\n/g' | sort |uniq -c
      2 a
      1 be
      2 file
      2 is
      1 supposed
      1 that
      1 this
      1 to

sortie lorsque canalisé juste pour trier:

root@sanctum:~/datascience# cat data | sed 's/ /\n/g' | sort 
a
a
be
file
file
is
is
supposed
that
this
to

comment le numéro de ligne d'apparence d'une ligne a-t-il un effet sur le nombre d'occurrences dans le fichier? je ne sais pas comment le formuler mais vous obtenez le point

Fondamentalement, pourquoi ne peux pas cat data | sed 's/ /\n/g' | uniq -c donne le résultat souhaité?

1
juggernauthk108

Ce n'est pas un comportement aléatoire. De man uniq:

Remarque: 'uniq' ne détecte pas les lignes répétées à moins qu'elles ne soient adjacentes. Vous voudrez peut-être d'abord trier l'entrée ou utiliser 'sort -u' sans 'uniq'. De plus, les comparaisons respectent les règles spécifiées par 'LC_COLLATE'.

Essentiellement, uniq par défaut ne fonctionne que sur l'entrée triée. Il en est ainsi par conception, en d'autres termes.

Cependant, votre question principale est:

comment le numéro d'apparence d'une ligne a-t-il un effet sur le nombre d'occurrences dans le fichier

Pour répondre à cette question, il faudrait vraiment regarder le code source:

 while (!feof (stdin))
    {
      char *thisfield;
      size_t thislen;
      if (readlinebuffer_delim (thisline, stdin, delimiter) == 0)
        break;
      thisfield = find_field (thisline);
      thislen = thisline->length - 1 - (thisfield - thisline->buffer);
      if (prevline->length == 0
          || different (thisfield, prevfield, thislen, prevlen))
        {
          fwrite (thisline->buffer, sizeof (char),
                  thisline->length, stdout);

          SWAP_LINES (prevline, thisline);
          prevfield = thisfield;
          prevlen = thislen;
        }
    }

La clé ici est que le fichier est lu ligne par ligne et la comparaison ne peut être effectuée qu'avec la ligne actuelle et la ligne précédente dans la fonction different() qui renvoie True si les lignes ne sont pas les mêmes , Faux s'ils sont identiques. La raison en est que si vous comparez avec toutes les lignes , vous aurez probablement besoin d'une grande quantité de mémoire s'il y a un grand nombre de lignes. Ce n'est pas pratique et ralentirait considérablement uniq

2