IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Contribuez / Téléchargez Sources et Outils PHP Discussion :

Trouver l'occurence la plus proche dans un tableau


Sujet :

Contribuez / Téléchargez Sources et Outils PHP

  1. #1
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut Trouver l'occurence la plus proche dans un tableau
    Bonjour à tous,

    Aujourd'hui, j'ai eu besoin d'un algo pour trouver le mot le plus proche dans une liste. Vu que ça existait pas et que je n'arrivais pas à le faire simplement avec array_map ou array_walk, j'ai codé une fonction que voici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    function array_find_closest ($needle, $haystack, $approx = 3) {
    	if (($offset = array_search($needle, $haystack)) !== false)
    		return $haystack[$offset];
     
    	foreach ($haystack as $item) {
    		$lev = levenshtein($needle, $item);
     
    		// if needle is completely different
    		if ($lev >= strlen($item))
    			continue;
     
    		// if word is 'too' different
    		if ($lev > $approx)
    			continue;
     
    		$guess[$item] = $lev;
    	}
     
    	if (empty($guess))
    		return false;
     
    	asort($guess);
    	return key($guess);
    };
    La fonction retourne false si aucune correspondance n'a été trouvée.

    Note: le troisième paramètre vous permet de déterminer la 'distance' maximum acceptable. Il représente le nombre maximum de caractère différents, à ajouter ou à soustraire pour trouver une correspondance.

    Attention: cette fonction utilise l'algorithme de levenshtein pour déterminer les correspondances possibles, cet algo est assez lourd et rends la fonction assez gourmande.

    Usage:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    $colors = array('orange', 'blue', 'yellow', 'pink', 'black', 'white');
     
    var_dump( array_find_closest('blu', $colors) ); // 'blue'
    var_dump( array_find_closest('P1nk', $colors) ); // 'pink'
    var_dump( array_find_closest('color is black', $colors) ); // false (trop de différences)
     
    var_dump( array_find_closest('Bl4cK', $colors) ); // 'black'
    var_dump( array_find_closest('Bl4cK', $colors, 2) ); // false (il faut changer 3 caractère pour arriver à 'black' mais 2 seulement sont autorisés)
    Voilà, si quelqu'un à des idées pour réduire la complexité ou améliorer en quoi que ce soit, les remarques sont les bienvenues.

  2. #2
    Expert éminent sénior

    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    7 920
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 7 920
    Points : 10 726
    Points
    10 726
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function array_find_closest($needle, $haystack, $approx = 3)
    {
        if (in_array($needle, $haystack)) {
            return $needle;
        }
     
        $distances = array();
     
        foreach ($haystack as $word) {
            $distance = levenshtein($needle, $word);
            if ($distance <= $approx) {
                $distances[$word] = $distance;
            }
        }
     
        asort($distances);
     
        return $distances ? key($distances) : false;
    }
    pas grand chose

  3. #3
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Pourquoi avoir viré cette sécurité ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    		// if needle is completely different
    		if ($lev >= strlen($item))
    			continue;

  4. #4
    Expert éminent sénior

    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    7 920
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 7 920
    Points : 10 726
    Points
    10 726
    Par défaut
    Citation Envoyé par Benjamin Delespierre Voir le message
    Pourquoi avoir viré cette sécurité ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    		// if needle is completely different
    		if ($lev >= strlen($item))
    			continue;
    on la déjà avec $approx

  5. #5
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Je l'avais mis pour éviter ce cas de figure:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    function array_find_closest($needle, $haystack, $approx = 3)
    {
        if (in_array($needle, $haystack)) {
            return $needle;
        }
     
        $distances = array();
     
        foreach ($haystack as $word) {
            $distance = levenshtein($needle, $word);
            if ($distance <= $approx) {
                $distances[$word] = $distance;
            }
        }
     
        asort($distances);
     
        return $distances ? key($distances) : false;
    }
     
    $haystack = array('defghi', 'abc');
    $needle = 'ghi';
     
    var_dump( array_find_closest($needle, $haystack) ); // 'abc'

  6. #6
    Expert éminent sénior

    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    7 920
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 7 920
    Points : 10 726
    Points
    10 726
    Par défaut
    oui bien joué

  7. #7
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Donc voici une version un poil mieux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function array_find_closest($needle, array $haystack, $approx = 3) {
        if (in_array($needle, $haystack)) {
            return $needle;
        }
     
        $distances = array();
        foreach ($haystack as $word) {
            $distance = levenshtein($needle, $word);
            if ($distance >= strlen($word))
                    continue;
            if ($distance <= $approx)
                $distances[$word] = $distance;
        }
     
        asort($distances);
        return $distances ? key($distances) : false;
    }
    merci à Stealth

  8. #8
    Membre du Club
    Inscrit en
    Janvier 2005
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 67
    Points : 47
    Points
    47
    Par défaut
    Citation Envoyé par Benjamin Delespierre Voir le message
    Donc voici une version un poil mieux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function array_find_closest($needle, array $haystack, $approx = 3) {
        if (in_array($needle, $haystack)) {
            return $needle;
        }
     
        $distances = array();
        foreach ($haystack as $word) {
            $distance = levenshtein($needle, $word);
            if ($distance >= strlen($word))
                    continue;
            if ($distance <= $approx)
                $distances[$word] = $distance;
        }
     
        asort($distances);
        return $distances ? key($distances) : false;
    }
    merci à Stealth
    Bjr,

    C'est bizarre, mais lorsqu'on rajoute le mot "zombie" à la fin du tableau dictionnaire des mots, et que l'on recherche "zo" ou "zom" on a pas le résultat escompté.

    BR

  9. #9
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Ta recherche n'est pas assez proche, le nombre de caractère différents est supérieur à $approx.

    Ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $haystack = array(
    	'ghoul',
    	'orc',
    	'goblin',
    	'salad-shaped-pork',
    	'zombie',
    );
     
    $needles = array(
    	'zo',
    	'zom',
    	'zomb',
    );
     
    foreach ($needles as $needle)
    	var_dump( array_find_closest($needle, $haystack) );
    Résutlats:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    boolean false // 'zo' est différent de zombie de 'zombie' de 4 caractères, donc 1 de trop
    string 'zombie' (length=6) // 'zom' est différent de 'zombie' de 3 caractères, ça passe
    string 'zombie' (length=6) // etc.
    Normalement, cette fonction doit être utilisée pour des recherches ou seuls quelques caractères sont différents par exemple entre "Ferrari" et "ferari".
    Donc si tu veux faire une recherche plus 'lâche', tu dois modifier le paramètre $approx

Discussions similaires

  1. Trouver la valeur la plus proche dans une ligne
    Par tavita987 dans le forum Excel
    Réponses: 5
    Dernier message: 05/02/2014, 11h12
  2. Réponses: 5
    Dernier message: 02/01/2014, 10h26
  3. [LV 2009] Valeur la plus proche dans un tableau
    Par K-RK-S dans le forum LabVIEW
    Réponses: 3
    Dernier message: 03/02/2011, 13h42
  4. trouver valeur la plus proche dans une colonne
    Par niepoc dans le forum Général Python
    Réponses: 10
    Dernier message: 05/06/2009, 15h02
  5. trouver la valeur la plus élevée dans un tableau
    Par denis.ws dans le forum Collection et Stream
    Réponses: 7
    Dernier message: 16/05/2008, 07h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo