Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

lignes de A qui ne sont pas dans B

14 réponses
Avatar
mpg
Bonjour,

Soit deux fichiers A et B contenant chacun une liste de mots, un par ligne.
Je souhaite connaître tous les mots de A qui ne sont pas dans B. Pour le
moment, je fais :

sort -u A > A.trie
sort -u B > B.trie
diff A.trie B.trie | grep '^<'

Y a-t'il moyen de faire ça sans passer par les fichiers intermédiaires
A.trie et B.trie ? Pour l'instant, je ne vois pas trop comment utiliser
diff au milieu d'un pipe, ni comment faire ça sans passer par diff.

Ce n'est franchement pas très important, passer par les fichiers
intermédiaires ne me dérange pas en pratique, c'est plutôt pour apprendre.

Merci d'avance.

Manuel.

10 réponses

1 2
Avatar
Benoit Izac
Bonjour,

le 24/11/2007 à 02:03, mpg a écrit dans le message
<fi7t8h$2vbl$ :

Soit deux fichiers A et B contenant chacun une liste de mots, un par
ligne. Je souhaite connaître tous les mots de A qui ne sont pas dans
B. Pour le moment, je fais :

sort -u A > A.trie
sort -u B > B.trie
diff A.trie B.trie | grep '^<'

Y a-t'il moyen de faire ça sans passer par les fichiers intermédiaires
A.trie et B.trie ? Pour l'instant, je ne vois pas trop comment
utiliser diff au milieu d'un pipe, ni comment faire ça sans passer par
diff.

Ce n'est franchement pas très important, passer par les fichiers
intermédiaires ne me dérange pas en pratique, c'est plutôt pour
apprendre.


Si l'ordre dans lequel tes lignes apparaissent ne t'importe pas, tu peux
utiliser le script suivant :

#!/usr/bin/perl
use warnings;
use strict;

if (@ARGV != 2) {
print "usage: $0 file1 file2n";
exit 1;
}

my %h;

open(my $a, "<", $ARGV[0]) or die "can't open $ARGV[0]: $!n";
$h{$_}++ foreach (<$a>);
close($a);

open(my $b, "<", $ARGV[1]) or die "can't open $ARGV[1]: $!n";
$h{$_}-- foreach (<$b>);
close($b);

foreach (keys %h) {
print if ($h{$_} > 0);
}
__END__

--
Benoit Izac

Avatar
Nicolas George
Benoit Izac wrote in message :
open(my $a, "<", $ARGV[0]) or die "can't open $ARGV[0]: $!n";
$h{$_}++ foreach (<$a>);
close($a);

open(my $b, "<", $ARGV[1]) or die "can't open $ARGV[1]: $!n";
$h{$_}-- foreach (<$b>);
close($b);


Mettre le deuxième en premier, et remplacer le premier par :

print unless $h{$_};

est plus efficace et préserve l'ordre.

Avatar
Nicolas George
mpg wrote in message <fi7t8h$2vbl$:
sort -u A > A.trie
sort -u B > B.trie
diff A.trie B.trie | grep '^<'


grep -Fxf B A

Avatar
Nicolas George
Nicolas George wrote in message
<4747f1ec$0$12374$:
sort -u A > A.trie
sort -u B > B.trie
diff A.trie B.trie | grep '^<'
grep -Fxf B A



Je remarque que ma version ne fait pas la même chose que la tienne ni celle
de Benoît. Mais c'est la seule qui colle à l'énoncé que tu as donné.


Avatar
Benoit Izac
Bonjour,

le 24/11/2007 à 10:40, Nicolas George a écrit
dans le message <4747f187$0$12374$ :

Benoit Izac wrote in message :
open(my $a, "<", $ARGV[0]) or die "can't open $ARGV[0]: $!n";
$h{$_}++ foreach (<$a>);
close($a);

open(my $b, "<", $ARGV[1]) or die "can't open $ARGV[1]: $!n";
$h{$_}-- foreach (<$b>);
close($b);


Mettre le deuxième en premier, et remplacer le premier par :

print unless $h{$_};

est plus efficace et préserve l'ordre.


Absolument. Le problème c'est que dans la demande de l'OP, il n'est pas
précisé ce qu'il faut faire lorsque une ligne apparaît par exemple
deux fois dans A et une fois dans B. Pour garder le même comportement :

print if (++$h{$_} > 0);

--
Benoit Izac


Avatar
Jacques L'helgoualc'h
Le 24-11-2007, mpg a écrit :
Bonjour,


bonjour,

Soit deux fichiers A et B contenant chacun une liste de mots, un par ligne.
Je souhaite connaître tous les mots de A qui ne sont pas dans B. Pour le
moment, je fais :

sort -u A > A.trie
sort -u B > B.trie
diff A.trie B.trie | grep '^<'

Y a-t'il moyen de faire ça sans passer par les fichiers intermédiaires
A.trie et B.trie ?


testé sous bash :

diff <(sort -u A) <(sort -u B)

Les options diff -y --suppress-common-lines peuvent servir mais ne
semblent pas répondre à ta question, sauf quand B est inclus dans A.
--
Jacques L'helgoualc'h

Avatar
Benoit Izac
Dans le message , le 24/11/2007 à 11:12, j'ai

print unless $h{$_};

est plus efficace et préserve l'ordre.


Absolument. Le problème c'est que dans la demande de l'OP, il n'est pas
précisé ce qu'il faut faire lorsque une ligne apparaît par exemple
deux fois dans A et une fois dans B. Pour garder le même comportement :

print if (++$h{$_} > 0);


Oubliez cette remarque, le -u de sort précise ce qu'il veut en faire.

--
Benoit Izac qui va reprendre un peu de café...


Avatar
Stephane Chazelas
On Sat, 24 Nov 2007 02:03:13 +0100, mpg wrote:
Bonjour,

Soit deux fichiers A et B contenant chacun une liste de mots, un par ligne.
Je souhaite connaître tous les mots de A qui ne sont pas dans B. Pour le
moment, je fais :

sort -u A > A.trie
sort -u B > B.trie
diff A.trie B.trie | grep '^<'

Y a-t'il moyen de faire ça sans passer par les fichiers intermédiaires
A.trie et B.trie ? Pour l'instant, je ne vois pas trop comment utiliser
diff au milieu d'un pipe, ni comment faire ça sans passer par diff.
[...]


comm -23 <(sort -u A) <(sort -u B)

<(...) appelé "process substitution" est une fonctionalité
non-standard de zsh, bash et certains ksh.

Sinon on peut faire:

sort -u A | { exec 3<&0; sort -u B | comm -23 /dev/fd/3 -; }

--
Stephane

Avatar
mpg
Le (on) samedi 24 novembre 2007 11:24, Benoit Izac a écrit (wrote) :

Dans le message , le 24/11/2007 à 11:12, j'ai

print unless $h{$_};

est plus efficace et préserve l'ordre.


Absolument. Le problème c'est que dans la demande de l'OP, il n'est pas
précisé ce qu'il faut faire lorsque une ligne apparaît par exemple
deux fois dans A et une fois dans B. Pour garder le même comportement :

print if (++$h{$_} > 0);


Oubliez cette remarque, le -u de sort précise ce qu'il veut en faire.

Ceci dit c'est une bonne remarque, car dans un premier temps je n'avais pas

envisagé le fait que A puisse contenir des doublons, donc pas mis le -u, et
eu bien des surprises...

Manuel.



Avatar
mpg
Le (on) samedi 24 novembre 2007 10:42, Nicolas George a écrit (wrote) :

grep -Fxf B A


Waouh. J'adore grep. Merci !

Ceci dit, comme dans la pratique (mais je ne l'ai pas précisé, j'ai eu
tort), j'applique en fait un coup de sed à chacun des fichiers (justement
pour les mettre sous la forme un mot par ligne), les autres réponses
utilisant <(...) me seront quand même bien utiles.

Manuel.

1 2