Или даже вы можете перейти к интерфейсу, считая, что требуется небольшое ограничение:
public interface IControllable
{
void Move(int step);
void Backward(int step);
}
public interface ITurnable
{
void TurnLeft(float angle);
void TurnRight(float angle);
}
public class Airplane : IControllable, ITurnable
{
void Move(int step)
{
// TODO: Implement code here...
}
void Backward(int step)
{
// TODO: Implement code here...
}
void TurnLeft(float angle)
{
// TODO: Implement code here...
}
void TurnRight(float angle)
{
// TODO: Implement code here...
}
}
Однако вам придется реализовать все объявление функции как IControllable
, так и ITurnable
в противном случае произойдет ошибка компилятора. Если вам нужна дополнительная реализация virutal, вам нужно будет пойти abstract class
для виртуального метода с interface
для чистого виртуального метода.
На самом деле существует разница между функцией interface
и abstract
функция interface
объявляет только функцию, вся функция interface
должна быть общедоступной, поэтому нет свойства fancy class, такого как private
или protected
, поэтому она очень быстрая, а функция abstract
- это метод фактического класса без реализация и принудительное выполнение в производном классе, поэтому вы можете поместить private
, protected
и переменные-члены доступа с функциями abstract
, и большую часть времени это медленнее, потому что отношения наследования класса анализируются во время выполнения. (aka vtable)
Мне наконец удалось это сделать. это не лучшее решение, но оно работает. Также, если у нас более 10 элементов, процесс начинает замедляться, потому что он умножается каждый раз, когда мы добавляем новый элемент:
public function generateAllCases($arr1, $arr2, $resultArr, &$index, $firstCall = false)
{
$shifted = false;
foreach ($arr1 as $elm)
{
foreach ($arr2 as $i => $vis)
{
if(!$shifted)
{
array_shift($arr1);
$shifted = true;
}
if(!isset($resultArr[$index]) || !isset($resultArr[$index][$elm]))
{
$resultArr[$index][$elm] = $vis;
}
else
{
$prevItem = $resultArr[$index];
$index++;
$resultArr[$index] = $prevItem;
$resultArr[$index][$elm] = $vis;
}
$resultArr = $this->generateAllCases($arr1, $arr2, $resultArr, $index);
}
break;
}
if($firstCall)
{
$allResults = [];
foreach ($resultArr as $k => $v)
{
$allResults[implode('.', $v)] = $v;
}
$allResults = array_values($allResults);
return $allResults;
}
return $resultArr;
}
называется так:
$index = 0;
$cases = $rpd->generateAllCases(['a', 'b', 'c'], [true, false], [], $index, true);
Кажется, вы ищете все перестановок с повторением всех элементов в $arr2
с длиной числа элементов в $arr1
.
Если это так, должно работать следующее:
<?php
declare(strict_types=1);
error_reporting(-1);
ini_set('display_errors', 'On');
function pwr(array $elements, int $k, int $idx = 0, array &$result = []): \Generator
{
foreach ($elements as $element) {
$result[$idx] = $element;
if ($k - $idx > 1) {
yield from pwr($elements, $k, $idx + 1, $result);
}
else {
yield $result;
}
}
}
function gen(array $keys, array $values): \Generator
{
foreach (pwr($values, \count($keys)) as $set) {
yield array_combine($keys, $set);
}
}
// this is just to test the result in a more *visual* way
foreach (gen(range('a', 'j'), [true, false]) as $case) {
foreach ($case as $k => $v) {
echo $v ? $k : '_';
}
echo "\n";
}
Чтобы избежать проблем с памятью, вы можете использовать yield
, но если массив абсолютно необходим, используйте [114 ] .
Очевидно, что это растет очень быстро (\count($arr2) ** \count($arr1)
), поэтому будьте осторожны при использовании iterator_to_array
.
Демонстрация: https://3v4l.org/l5PRo