lignes de A qui ne sont pas dans B

Le
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.
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Benoit Izac
Le #119550
Bonjour,

le 24/11/2007 à 02:03, mpg a écrit dans le message

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

Nicolas George
Le #119549
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.

Nicolas George
Le #119548
mpg wrote in message
sort -u A > A.trie
sort -u B > B.trie
diff A.trie B.trie | grep '^<'


grep -Fxf B A

Nicolas George
Le #119547
Nicolas George wrote in message
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é.


Benoit Izac
Le #119546
Bonjour,

le 24/11/2007 à 10:40, Nicolas George a écrit
dans le message
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


Jacques L'helgoualc'h
Le #119545
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

Benoit Izac
Le #119544
Dans le message
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é...


Stephane Chazelas
Le #119542
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

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

Dans le message
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.



mpg
Le #119414
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.

Publicité
Poster une réponse
Anonyme