Используя предопределенный массив чисел, как я могу использовать PHP для создания многомерного массива, который группирует все пары факторов по их продукту?
Входной массив:
$array = array(1,2,3,4,5,6,7,8);
Я хочу отобразить все пары факторов для каждой группы продуктов, которые имеют более одной пары факторов.
В случае, когда нет групп продуктов, которые имеют более одной пары факторов, No pairs Found
должен отображаться.
Учитывая приведенные выше данные, это мой ожидаемый результат:
1 6 and 2 3 // product group = 6
1 8 and 2 4 // product group = 8
2 6 and 3 4 // product group = 12
3 8 and 4 6 // product group = 24
* обратите внимание, что при увеличении размера входного массива на выходе будет отображаться более двух пар факторов на группу.
Это мой код из C ++:
void findPairs(int arr[], int n)
{
bool found = false;
unordered_map<int, pair < int, int > > H;
for (int i=0; i<n; i++)
{
for (int j=i+1; j<n; j++)
{
// If product of pair is not in hash table,
// then store it
int prod = arr[i]*arr[j];
if (H.find(prod) == H.end())
H[prod] = make_pair(i,j);
// If product of pair is also available in
// then print current and previous pair
else
{
pair<int,int> pp = H[prod];
cout << arr[pp.first] << " " << arr[pp.second]
<< " and " << arr[i]<<" "<<arr[j]<<endl;
found = true;
}
}
}
// If no pair find then print not found
if (found == false)
cout << "No pairs Found" << endl;
}
Это ваш код на C ++, «переведенный» на PHP (в основном по поиску & заменить).
90% перевода было достигнуто путем удаления типов переменных и добавления к ним имен переменных $
, array
Тип PHP представляет собой смесь массива, списка и карты (он же хэш, словарь) и может использоваться как для $H
и значения, которые он содержит (пары значений).
function findPairs(array $arr, $n)
{
$found = false;
$H = array();
for ($i=0; $i<$n; $i++)
{
for ($j=$i+1; $j<$n; $j++)
{
// If product of pair is not in hash table,
// then store it
$prod = $arr[$i]*$arr[$j];
if (! array_key_exists($prod, $H))
$H[$prod] = array($i,$j);
// If product of pair is also available in
// then print current and previous pair
else
{
$pp = $H[$prod];
echo $arr[$pp[0]], " ", $arr[$pp[1]]
, " and ", $arr[$i], " ", $arr[$j], "\n";
$found = true;
}
}
}
// If no pair find then print not found
if ($found == false)
echo "No pairs Found\n";
}
$array = array(1,2,3,4,5,6,7,8);
findPairs($array, count($array));
И это его вывод:
1 6 and 2 3
1 8 and 2 4
2 6 and 3 4
3 8 and 4 6
Самое простое решение будет хорошо работать с небольшим массивом, как ваш пример, но будет использовать много памяти для больших входов. По сути, сначала рассчитайте все продукты, используя вложенный цикл. Для каждого продукта создайте список входов, которые генерируют продукт. Имейте в виду, что может быть более двух способов получить определенный результат, поэтому вы можете получить такой результат, как 1 12 and 2 6 and 3 4
для больших списков.
Для ввода размера N вам нужно хранить ((N -1) * N) / 2 кортежей в памяти, так что об этом следует помнить.
$input = [1, 2, 3, 4, 5, 6, 7, 8];
$products = [];
foreach ($input as $index1 => $value1) {
// Assuming you only want unique combinations, only combine this value with the other values coming after it
for ($index2 = $index1 + 1; $index2 < count($input); $index2++) {
$value2 = $input[$index2];
$product = $value1 * $value2;
// Make sure there is an entry in the $products array for adding this input to
if (!isset($products[$product])) {
$products[$product] = [];
}
// Add this input (formatted) to the list of possible inputs resulting in this product
$products[$product][] = sprintf('%d %d', $value1, $value2);
}
}
// Print all inputs resulting in the same products, if there are more than 1 way to produce the same output
foreach ($products as $inputs) {
if (count($inputs) > 1) {
echo implode(' and ', $inputs), PHP_EOL;
}
}
Будет выходной
1 6 and 2 3
1 8 and 2 4
2 6 and 3 4
3 8 and 4 6
<?php
ini_set("display_errors", 1);
$result=array();
$array = array(1,2,3,4,5,6,7,8);
$counter=0;
$noOfPairs=3;
while (count($result)!=$noOfPairs)
{
shuffle($array);
getPair($array);
}
print_r($result);
function getPair($array)
{
global $result;
$product=$array[0]*$array[1];
if(isset($result[$product]))
{
return false;
}
$result[$product][]=array($array[0],$array[1]);
unset($array[0]);
unset($array[1]);
foreach($array as $key1 => $value1)
{
foreach($array as $key2 => $value2)
{
if($value1*$value2==$product)
{
$result[$product][]=array($value1,$value2);
break;
}
}
if(count($result[$product])==2)
{
break;
}
}
if(count($result[$product])==1)
{
unset($result[$product]);
}
}
Я не проверил скорость своего метода, но думаю, что он более прямой и легче для чтения.
По сути, он генерирует полный многомерный массив, затем отфильтровывает любые подмассивы, которые имеют только одну пару, а затем, если остаются подмассивы, отображает их. Просто.
Мой метод работает без каких-либо count()
звонки и без приращения ключевых переменных. Использует очень быстро isset()
вызов, чтобы отфильтровать массив результатов и array_walk()
итерировать и implode()
квалифицирующие подмассивы.
В качестве бонуса я использовал range()
динамически генерировать входной массив, который определяется путем ввода наибольшего значения для массива. Конечно, если вы хотите найти пары для [3,4,5]
Затем вам придется изменить этот процесс или просто вернуться к своему первоначальному стилю — это зависит от ожиданий вашего проекта.
Код: (демонстрация)
function findPairs($maxfactor){
$array=range(1,$maxfactor); // spare yourself having to write out the array
foreach($array as $v1){
$array=array_slice($array,1); // shrink array as you go to avoid needless iterations
foreach($array as $v2){
$result[$v1*$v2][]="$v1 $v2"; // generate multi-dim output array using products as outer keys
}
}
$result=array_filter($result,function($a){return isset($a[1]);}); // remove elements with < 2 pairs
if(!$result){
echo "No pairs found";
}else{
array_walk($result,function($a){echo implode(' and ',$a),"\n";});
}
}
findPairs(8);
Выход:
1 6 and 2 3
1 8 and 2 4
2 6 and 3 4
3 8 and 4 6