У меня есть этот массив:
$arr = array (20, 1, 5, 10, 7, 16);
Я хотел бы получить 5
и 7
. Потому что они ближе друг к другу, чем другие предметы. Другими словами, разница между ними – самое низкое число:
7 - 5 = 2 // 2 is lowest number as the difference between all array's items
Как я могу это сделать?
$keep = $arr[0]; $diff = $arr[1] - $arr[0]; foreach ($arr as $item) { if ( ($keep - $item) < $diff && $keep != $item ) { $diff = $item; } }
Мой код неполный, потому что он просто сравнивает первый элемент с другими элементами.
Таким образом, чтобы получить два числа в массиве, которые наиболее близки друг к другу, вам нужно сравнить каждое значение друг с другом. Но вам не нужно сравнивать их с собой и с предыдущими, которые вы уже сравнили.
Чтобы рассчитать, сколько сравнений вы должны сделать, вы можете использовать биномиальный коэффициент :
(n) n! (k) → ───────────── k! * (n - k)!
Где n – общее количество элементов и k, сколько вы выбираете
И в вашем примере это означало бы:
n = 6 //Array elements k = 2 //Two values which you compare 6! 720 ───────────── → ───────────── = 15 comparison 2! * (6 - 2)! 2 * 24
Визуализация
20 , 1 , 5 , 10 , 7 , 16 //Array values ↓ ↑ ↑ ↑ ↑ ↑ └────┴───┴───┴────┴───┘ //20 compared to all values, except itself ↓ ↑ ↑ ↑ ↑ └───┴───┴────┴───┘ //1 compared to all values, except itself + [20] ↓ ↑ ↑ ↑ └───┴────┴───┘ //5 compared to all values, except itself + [20, 1] ↓ ↑ ↑ └────┴───┘ //10 compared to all values, except itself + [20, 1, 5] ↓ ↑ └───┘ //7 compared to all values, except itself + [20, 1, 5, 10] //16 compared to all values, except itself + [20, 1, 5, 10, 7]
Теперь, чтобы сделать это в коде, нам нужно 2 цикла, чтобы перебрать весь массив для каждого значения первого цикла. Но, как мы уже говорили, мы можем игнорировать само значение и предыдущие значения, поэтому для этого мы используем 2 для циклов и устанавливаем ключ для внутреннего цикла как внешний ключ + 1.
for($key = 0, $length = count($arr); $key < $length; $key++){ for( $innerKey = $key + 1 ; $innerKey < $length; $innerKey++){ //↑ Skipping the previous values and the value itself } }
Во внутреннем цикле нам просто нужно получить доступ к текущему значению внешнего цикла и получить разницу по сравнению со значением внутреннего цикла. То, что это также работает с отрицательными числами, мы просто переносим на вызов abs()
чтобы сделать разницу всегда положительной.
Затем мы просто проверяем, меньше ли разница, чем самая маленькая разница, которую мы уже нашли, сохраненная в $nearest
. (Мы инициализировали $nearest
к разнице наибольшего и наименьшего значения массива + 1):
if( ($diff = abs($arr[$keys[$key]] - $arr[$keys[$innerKey]])) < $nearest)
Если разность меньше наименьшей разницы, которую мы уже нашли, мы записываем два значения в массив и устанавливаем самую маленькую разницу:
$result = [$arr[$keys[$key]], $arr[$keys[$innerKey]]]; $nearest = $diff;
<?php $arr = [20, 1, 5, 10, 7, 16]; $keys = array_keys($arr); $nearest = max($arr) - min($arr) + 1; $result = []; for($key = 0, $length = count($arr); $key < $length; $key++){ for($innerKey = $key + 1; $innerKey < $length; $innerKey++){ if( ($diff = abs($arr[$keys[$key]] - $arr[$keys[$innerKey]])) < $nearest){ $result = [$arr[$keys[$key]], $arr[$keys[$innerKey]]]; $nearest = $diff; } } } print_r($result); ?>
Вывод
[5, 7]
usort
используется PHPusort
, как примечание, которое реализовано с помощью quicksort.
$temp
==> Временный массив для хранения двух значений и их различий при циклизации
$temp = [arr[$i] , arr[$j] , arr[$i]-arr[$j] ]
$arr = array (20, 1, 5, 10, 7, 16); $temp=array(); for ($i = 0; $i < count($arr)-1; $i++) { $diff=0; for ($j = $i+1; ($j < count($arr) && $i!=$j); $j++) { $diff=abs($arr[$i]-$arr[$j]); //finding difference &taking absolute $temp[] = array($arr[$i],$arr[$j], $diff); } } usort($temp,function ($a, $b) { return $b[2] < $a[2]; });//sort `$temp[]` in ascending order according to the difference value list($x,$y,$d) = $temp[0]; //the first row of `$temp` contains values with the diff. is lowest //and the values is stored to `$x` & `$y` and there difference in `$d` echo "Related Values are $x and $y by $d";
Проверить результаты здесь http://ideone.com/pZ329m
За работой
20 1 5 10 7 16 //inner loop ----------------------- | | | | | | $temp[]=[[20,1,19],[20,5,15],[20,10,10],...//$i=0 |// `20` is compared values from 1 onwards and the values and differences are stored in `$temp[]` |___|____|___|___|___| //(eg., $temp=[20,1,|20-1|]) //$j=1,2,3,4,5↓ | | | | | [1,5,4],[1,10,9],... //$i=1 | `1` is compared with values from 5 onwards |____|___|___|___| //$j=2,3,4,5 ↓outer loop | | | | [5,10,5],[5,7,2],... //$i=2 | `5` is compared with values from 10 onwards |___|___|___| //$j=3,4,5 ↓ | | | [10,7,3],[10,16,6] //$i=3 | `10` is compared with values from 7 onwards |___|___| //$j=4,5 ↓ | | [7,16,9]] //$i=4 |`7` is compared with final value `16` |___| //$j=5 ↓
Получив
$temp[]
, он сортируется в порядке возрастания в соответствии сdifferences
.
Тогда первая строка$temp[]
дает наш желаемый результат.
Что внутри $temp[]
Array ( [0] => Array ( [0] => 7 [1] => 5 [2] => 2 ) [1] => Array ( [0] => 7 [1] => 10 [2] => 3 ) [2] => Array ( [0] => 16 [1] => 20 [2] => 4 ) [3] => Array ( [0] => 5 [1] => 1 [2] => 4 ) [4] => Array ( [0] => 10 [1] => 5 [2] => 5 ) [5] => Array ( [0] => 16 [1] => 10 [2] => 6 ) [6] => Array ( [0] => 7 [1] => 1 [2] => 6 ) [7] => Array ( [0] => 16 [1] => 7 [2] => 9 ) [8] => Array ( [0] => 10 [1] => 1 [2] => 9 ) [9] => Array ( [0] => 10 [1] => 20 [2] => 10 ) [10] => Array ( [0] => 16 [1] => 5 [2] => 11 ) [11] => Array ( [0] => 7 [1] => 20 [2] => 13 ) [12] => Array ( [0] => 5 [1] => 20 [2] => 15 ) [13] => Array ( [0] => 16 [1] => 1 [2] => 15 ) [14] => Array ( [0] => 1 [1] => 20 [2] => 19 ) )
Поскольку я комментирую использование цикла 2 и условия, я сделал то же самое. Просто проверьте это и дайте мне знать.
$arr = array (20, 1, 5, 10, 7, 16); $c = count($arr); $ld = max($arr); for($i = 0; $i < $c; $i++){ for($j = $i+1; $j < $c; $j++){ $abs = abs($arr[$i]-$arr[$j]); if($abs < $ld) $ld = $abs; } } echo $ld; //2
если вам нужно знать, какое из двух значений имеет разницу, то это возможно, просто сохраните их внутри условия if.
Ну, быстрая и грязная … две петли, одно условие
//$arr = array (20, 1, 5, 10, 7, 16); gives 5 and 7 $arr = array (-32,-15,4,6,-14,613,4,63,6,4); $diff = INF; foreach ($arr as $item0) { foreach ($arr as $item1) { $localdiff = abs($item0 - $item1); if ( $localdiff > 0 && $localdiff < $diff ) { $diff = $localdiff; $keep0 = $item0; $keep1 = $item1; } } } echo "Smallest distance was $diff, between $keep0 and $keep1";
Проверьте это на http://ideone.com/WdWOcb
использовать это
$arr = array (20, 1, 5, 10, 7, 16); $temp = array(); foreach ($arr as $item1) { foreach ($arr as $item2) { $aV = abs($item1-$item2); if(!in_array($aV, $temp) && $aV!=0) $temp[$item1."-".$item2] =$aV; } } $closest = array_keys($temp,min($temp)); list($first,$explode,$second) = $closest[0]; print "The two closest numbers are " . $first . " and " . $second;
$arr = array(20, 1, 5, 10, 7, 16); $min = max($arr); $closest = array(); foreach ($arr as $i) { foreach ($arr as $j) { if ($i != $j) { $diff = abs($i - $j); if ($min > $diff) { $min = $diff; $closest[0] = $i; $closest[1] = $j; } } } } print "The two closest numbers are " . $closest[0] . " and " . $closest[1];
Непонятно, что происходит в этой ситуации:
$arr = array( 14, 20, 1, 5, 10, 7, 16 );
В приведенном выше случае у вас есть две пары с 2 как разница (7-5, 16-14). Следующий код возвращает все относительные значения.
Мы выполняем стандартные два вложенных цикла для сравнения всех элементов (основной цикл, исключающий последний элемент, вложенный цикл, начинающийся с основного индекса +1), тогда, если разница между текущими значениями ниже, чем ранее полученная разница, мы ее заменяем; в противном случае, если разница равна предыдущей разнице, добавим новую пару:
$result = array( 'sum' => INF, 'values'=> array() ); for( $i=0; $i < count( $arr )-1; $i++ ) { for( $j = $i+1; $j < count( $arr ); $j++ ) { $dif = abs( $arr[$i] - $arr[$j] ); if( $dif < $result['sum'] ) { $result = array( 'sum' => $dif, 'values'=> array( array( $arr[$i], $arr[$j] ) ) ); } elseif( $dif == $result['sum'] ) { $result['values'][] = array( $arr[$i], $arr[$j] ); } } }
На этом этапе, для образца массива выше, вы получите следующий результат:
Array ( [sum] => 2 [values] => Array ( [0] => Array ( [0] => 14 [1] => 16 ) [1] => Array ( [0] => 5 [1] => 7 ) ) )
Если вас интересует все значение, просто вы можете найти их в $result['values']
. В противном случае, если вы хотите (т. usort
) Минимальные значения (5 и 7), вы можете usort
-it:
usort( $result['values'], function( $a, $b ) { return min($a)-min($b); } );
и используйте $result['values'][0]
:
[0] => Array ( [0] => 5 [1] => 7 )
попробуй это
$arr = array (20, 1, 5, 10, 7, 16); arsort($arr, SORT_NUMERIC); $arr = array_values( $arr ); $min = 0; foreach( $arr as $index => $number ){ if( isset($arr[$index+1]) ){ $diff = abs( $number - $arr[$index+1] ); if( $diff < $min || $min == 0 ){ $min = $diff; $result = array( $number, $arr[$index+1] ); } } } print_r( $result );