Défi n°4 : Comparer deux listes de mots
Venez relever les défis MATLAB.

Le , par ol9245, Membre éprouvé
J'ai deux listes de mots en nombre arbitraire et non ordonnées. Par exemple :
Code : Sélectionner tout
1
2
A = {'un' 'deux' 'chateau' 'trois' 'quatre'} ;
B = {'deux' 'quatre' 'six' 'huit' 'dix' 'douze' 'maison' 'bateau' 'chateau'} ;
Le défi est le suivant :
Écrire le code le plus compact(*) possible pour trouver tous les mots communs aux deux listes. c'est-à-dire quelque chose comme ça :
Code : Sélectionner tout
1
2
3
4
5
>>votre formule magique ici

ans = 

    'deux'    'chateau'    'quatre'
-----------------------------------
(*) un code est compact quand il a :
  • moins de boucles (for-end, while-end, ...)
  • moins de lignes de code
  • moins d'affectations (signe =)
  • moins de variables déclarées


Pas besoin de hiérarchiser ces critères car toute amélioration de l'un impacte les autres.


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse

Avatar de magelan magelan - Modérateur https://www.developpez.com
le 16/06/2012 à 23:39
Salut,

proposition avec cellfun justement :
Code : Sélectionner tout
1
2
3
4
5
A = {'un' 'deux' 'chateau' 'trois' 'quatre'} ;
B = {'deux' 'quatre' 'six' 'huit' 'dix' 'douze' 'maison' 'bateau' 'chateau'} ;
C = repmat(A,size(B,2),1)
D = repmat(B.',1,size(A,2))
E = cellfun(@(x,y)strfind(x,y), C, D,'UniformOutput',false)
ou en compactant encore plus :
Code : Sélectionner tout
1
2
3
A = {'un' 'deux' 'chateau' 'trois' 'quatre'} ;
B = {'deux' 'quatre' 'six' 'huit' 'dix' 'douze' 'maison' 'bateau' 'chateau'} ;
E = cellfun(@(x,y)strfind(x,y), repmat(A,size(B,2),1), repmat(B.',1,size(A,2)),'UniformOutput',false)
Juste une remarque pour préciser qu'un code compact n'est pas toujours un code optimisé et cela peut le rendre parfois illisible.
Avatar de ol9245 ol9245 - Membre éprouvé https://www.developpez.com
le 17/06/2012 à 0:08
Pour un début, la barre est assez haut : une seule instruction

Par contre tu n'obtiens pas la solution (je vais ajouter une précision dans l'énoncé). Je veux les trois chaines communes. Et toi, il te faut encore quelques instructions de plus pour les sortir :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
E = cellfun(@(x,y)strfind(x,y), repmat(A,size(B,2),1), repmat(B.',1,size(A,2)),'UniformOutput',false)

E = 

     []    [1]     []     []     []
     []     []     []     []    [1]
     []     []     []     []     []
     []     []     []     []     []
     []     []     []     []     []
     []     []     []     []     []
     []     []     []     []     []
     []     []     []     []     []
     []     []    [1]     []     []
Avatar de duf42 duf42 - Expert confirmé https://www.developpez.com
le 17/06/2012 à 11:04
Bonjour,

Je pense que la fonction INTERSECT doit faire l'affaire ici:
Code : Sélectionner tout
1
2
intersect(A,B)
Duf
Avatar de ol9245 ol9245 - Membre éprouvé https://www.developpez.com
le 17/06/2012 à 11:44
Citation Envoyé par duf42 Voir le message
Bonjour,

Je pense que la fonction INTERSECT doit faire l'affaire ici:
Code : Sélectionner tout
1
2
3
4
A = {'un' 'deux' 'chateau' 'trois' 'quatre'} ;
B = {'deux' 'quatre' 'six' 'huit' 'dix' 'douze' 'maison' 'bateau' 'chateau'} ;
intersect(A,B)
Duf

Bravo Duf !

0 boucle
0 variables intermédiaires
1 ligne de code,
1 fonction matlab appelée.

Je propose de t'accorder la victoire à ce défi

Mon idée de départ était celle-ci, que tu as largement battu :
Code : Sélectionner tout
1
2
3
4
A = {'un' 'deux' 'chateau' 'trois' 'quatre'} ;
B = {'deux' 'quatre' 'six' 'huit' 'dix' 'douze' 'maison' 'bateau' 'chateau'} ;
[a, b]=meshgrid(1:numel(A),1:numel(B)) ;
A(any(strcmp(A(a),B(b))))
Avatar de ol9245 ol9245 - Membre éprouvé https://www.developpez.com
le 17/06/2012 à 12:07
@Duf :

J'ai essayé d'appliquer ta solution dans mon code, mais mon problème n'est pas exactement celui que j'ai formulé dans le défi. Le défi est un problème symétrique. Le mien ne l'est pas.
J'ai une liste A de mots de référence (un dictionnaire) et une liste de mots B à chercher dans A. J'ai besoin des index des mots de B dans le dictionnaire A.
Voici un bout de code qui résume les deux solutions, appliquées au problème non symétrique. Qu'en penses-tu ?

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Dico = {'deux' 'quatre' 'six' 'huit' 'dix' 'douze' 'maison' 'bateau' 'chateau'} ;
Chercher = {'deux' 'chateau'} ;

% Duf
M = intersect(Dico, Chercher) ;
fprintf('\nLes mots communs sont -dans le désordre- (recette Duf) : ') ;
fprintf('%s ', M{:}) ;

% OL9245
[a, b]=meshgrid(1:numel(Dico),1:numel(Chercher)) ;
Ix = find(any(strcmp(Dico(a),Chercher(b)))) ;
fprintf('\nLeurs index dans le dico sont -dans l''ordre- (recette OL9245) : ') ;
fprintf('%d ', Ix) ;
fprintf('\n') ;
Résultat :
Code : Sélectionner tout
1
2
Les mots communs sont -dans le désordre- (recette Duf) : chateau deux 
Leurs index dans le dico sont -dans l'ordre- (recette OL9245) : 1 9
Avatar de Winjerome Winjerome - Expert éminent sénior https://www.developpez.com
le 17/06/2012 à 13:00
Salut,

Petit tour du côté de la doc :
[c, ia, ib] = intersect(a, b) also returns column index vectors ia and ib such that c = a(ia) and c = b(ib) (or c = a(ia,:) and c = b(ib,:)).
Donc à partir de là, ce n'est pas dur d'obtenir ces indices

Sinon, deux autres solutions :
Code : Sélectionner tout
1
2
3
4
5
6
A = {'un' 'deux' 'chateau' 'trois' 'quatre'} ;
B = {'deux' 'quatre' 'six' 'huit' 'dix' 'douze' 'maison' 'bateau' 'chateau'} ;

A(ismember(A,B))

A ( cellfun(@(a) any(strcmp(a,B)), A) )
Concernant ta solution ol9245, je rajouterais A(any(strcmp(A(a),B(b)),1)) dans le cas d'un seul mot à chercher.
Avatar de Jerome Briot Jerome Briot - Rédacteur/Modérateur https://www.developpez.com
le 17/06/2012 à 13:06
Et pour une solution encore plus spécifique que la solution "générale" de duf42 :

Code : Sélectionner tout
edit intersect
Avatar de tanguy4724 tanguy4724 - Membre habitué https://www.developpez.com
le 26/06/2012 à 15:34
sans aucun mérite car je ne fais que résumer les messages précédents :

Code : Sélectionner tout
1
2
3
[C,IA,IB] = INTERSECT(Dico, Chercher) ;
IA = sort(IA)
on a ainsi le résultat suivant :


Dico = {'deux' 'quatre' 'six' 'huit' 'dix' 'douze' 'maison' 'bateau' 'chateau'} ;
Chercher = {'deux' 'chateau'} ;
[C,IA,IB] = INTERSECT(Dico, Chercher) ;
IA = sort(IA)

IA =

1 9
Avatar de ol9245 ol9245 - Membre éprouvé https://www.developpez.com
le 26/06/2012 à 18:45
Ca nous fait donc deux lignes, donc autant que ma proposition, mais ++ joli et ++ compact.
Contacter le responsable de la rubrique MATLAB