72 votes

Trouver une valeur correspondante ou la plus proche dans un tableau

Comment puis-je chercher et trouver, pour une valeur cible donnée, la valeur la plus proche dans un tableau ?

Disons que j'ai ce tableau exemplaire :

array(0, 5, 10, 11, 12, 20)

Par exemple, lorsque je cherche avec la valeur cible 0, la fonction renvoie 0 ; lorsque je cherche avec 3, elle renvoie 5 ; lorsque je cherche avec 14, elle renvoie 12.

2 votes

Je ne sais pas ce que vous voulez faire.

0 votes

Il n'existe pas de fonction intégrée pour ce faire. Vous devrez écrire la vôtre. Vous devriez également envisager de demander à un véritable question dans votre question ; qu'est-ce qui vous pose problème actuellement ?

4 votes

@meagar je pense que la déclaration est très claire, ayant à demandez à une question n'est pas une obligation, n'est-ce pas ?

1voto

quantme Points 1417

Pour rechercher la valeur la plus proche dans un tableau d'objets, vous pouvez utiliser ce code adapté à partir de La réponse de Tim Cooper .

<?php
// create array of ten objects with random values
$images = array();
for ($i = 0; $i < 10; $i++)
    $images[ $i ] = (object)array(
        'width' => rand(100, 1000)
    );

// print array
print_r($images);

// adapted function from Tim Copper's solution
// https://stackoverflow.com/a/5464961/496176
function closest($array, $member, $number) {
    $arr = array();
    foreach ($array as $key => $value)
        $arr[$key] = $value->$member;
    $closest = null;
    foreach ($arr as $item)
        if ($closest === null || abs($number - $closest) > abs($item - $number))
            $closest = $item;
    $key = array_search($closest, $arr);
    return $array[$key];
}

// object needed
$needed_object = closest($images, 'width', 320);

// print result
print_r($needed_object);
?>

1voto

Thomas Bachem Points 661

La meilleure méthode que j'ai trouvée, basée sur La réponse de Piyush Dholariya :

$array = [4, 9, 15, 6, 2];
$goal = 7;

$closest = array_reduce($array, function($carry, $item) use($goal) {
    return (abs($item - $goal) < abs($carry - $goal) ? $item : $carry);
}, reset($array)); // Returns 6

0voto

k to the z Points 2204
function closestnumber($number, $candidates) {
    $last = null;
    foreach ($candidates as $cand) {
        if ($cand < $number) {
            $last = $cand;
        } elseif ($cand == $number) {
           return $number;
        } elseif ($cand > $number) {
           return $last;
        }
    }
    return $last;
}

1 votes

Cela nécessite-t-il que les valeurs du tableau soient triées ?

0 votes

Je pense que oui, et cette fonction n'a pas passé mon test unitaire pour une raison quelconque ( Failed asserting that 0 match expected 5. ) :(

0 votes

else if (comme deux mots) en php est une violation des normes de codage PSR-12. Vous devriez utiliser elseif (en un seul mot).

0voto

RobertPitt Points 28140

Vous pouvez simplement utiliser array_search pour cela, il renvoie une seule clé, s'il y a plusieurs instances de votre recherche dans le tableau, il renvoie la première qu'il trouve.

Citation de PHP :

Si l'aiguille est trouvée dans la botte de foin plus d'une fois, la première clé correspondante est retournée. Pour retourner les clés de toutes les valeurs correspondantes, utilisez array_keys() avec le paramètre optionnel search_value à la place.

Exemple d'utilisation :

if(false !== ($index = array_search(12,array(0, 5, 10, 11, 12, 20))))
{
    echo $index; //5
}

Mise à jour :

function findNearest($number,$Array)
{
    //First check if we have an exact number
    if(false !== ($exact = array_search($number,$Array)))
    {
         return $Array[$exact];
    }

    //Sort the array
    sort($Array);

   //make sure our search is greater then the smallest value
   if ($number < $Array[0] ) 
   { 
       return $Array[0];
   }

    $closest = $Array[0]; //Set the closest to the lowest number to start

    foreach($Array as $value)
    {
        if(abs($number - $closest) > abs($value - $number))
        {
            $closest = $value;
        }
    }

    return $closest;
}

0voto

llange Points 290

Considérant que le tableau d'entrée est trié dans l'ordre ascendant asort() par exemple, vous serez beaucoup plus rapide à effectuer une recherche en utilisant un recherche dichotomique .

Voici une adaptation rapide et sale d'un code que j'utilise pour insérer un nouvel événement dans un fichier de type Iterable liste d'événements triés par objets DateTime

Ainsi, ce code renverra le point le plus proche à gauche (avant / plus petit).

Si vous souhaitez trouver le point mathématiquement le plus proche : pensez à comparer la distance entre la valeur recherchée et la valeur de retour et le point immédiatement à droite (suivant) de la valeur de retour (s'il existe).

function dichotomicSearch($search, $haystack, $position=false)
{
    // Set a cursor between two values
    if($position === false)
    {    $position=(object)  array(
            'min' => 0,
            'cur' => round(count($haystack)/2, 0, PHP_ROUND_HALF_ODD),
            'max' => count($haystack)
            );
    }

    // Return insertion point (to push using array_splice something at the right spot in a sorted array)
    if(is_numeric($position)){return $position;}

    // Return the index of the value when found
    if($search == $haystack[$position->cur]){return $position->cur;}

    // Searched value is smaller (go left)
    if($search <= $haystack[$position->cur])
    {
        // Not found (closest value would be $position->min || $position->min+1)
        if($position->cur == $position->min){return $position->min;}

        // Resetting the interval from [min,max[ to [min,cur[
        $position->max=$position->cur;
        // Resetting cursor to the new middle of the interval
        $position->cur=round($position->cur/2, 0, PHP_ROUND_HALF_DOWN);
        return dichotomicSearch($search, $haystack, $position);
    }

    // Search value is greater (go right)
        // Not found (closest value would be $position->max-1 || $position->max)
        if($position->cur < $position->min or $position->cur >= $position->max){return $position->max;}
        // Resetting the interval from [min,max[ to [cur,max[
        $position->min = $position->cur;
        // Resetting cursor to the new middle of the interval
        $position->cur = $position->min + round(($position->max-$position->min)/2, 0, PHP_ROUND_HALF_UP);
        if($position->cur >= $position->max){return $position->max;}
        return dichotomicSearch($search, $haystack, $position);        
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X