Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/270.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用PHP计算数组与阈值的交集_Php_Arrays_Intersection - Fatal编程技术网

用PHP计算数组与阈值的交集

用PHP计算数组与阈值的交集,php,arrays,intersection,Php,Arrays,Intersection,假设我有以下数组: $a = [1,2,3,4,5]; $b = [1,3,4,5,6]; $c = [1,7,8,9,10]; $d = [1,2,3,4]; 它们的交集是$result=[1],这很简单。但是如果我想要最小阈值为3的交叉点呢?阈值意味着我可以从交叉点跳过一个或多个数组,只要生成的交叉点至少有3个元素,在这种情况下可能会导致: $result = [1,3,4]; 1、3和4存在于$a、b和$d中,但不存在于$c中,因为阈值而被跳过。是否有一个现有的PHP类、算法或函数可以

假设我有以下数组:

$a = [1,2,3,4,5];
$b = [1,3,4,5,6];
$c = [1,7,8,9,10];
$d = [1,2,3,4];
它们的交集是
$result=[1]
,这很简单。但是如果我想要最小阈值为3的交叉点呢?阈值意味着我可以从交叉点跳过一个或多个数组,只要生成的交叉点至少有3个元素,在这种情况下可能会导致:

$result = [1,3,4];

1、3和4存在于$a、b和$d中,但不存在于$c中,因为阈值而被跳过。是否有一个现有的PHP类、算法或函数可以用来实现这一点?

没有内置功能。你需要写一些简短的东西,比如:

$values = [];

foreach ([$a, $b, $c, $d] as $arr)
    foreach ($arr as $value)
        $values[$value] = ($values[$value] ?? 0) + 1;

// For threshold of 3
$values = array_keys(array_filter($values, function($a) { return $a >= 3; }));
注:这需要PHP7用于??操作人员否则,请使用以下内容:

$values[$value] = empty($values[$value]) ? 1 : $values[$value] + 1;

为此,我们必须使用数组的组合。我使用了这个算法的组合。通过调整此算法,我们可以编写以下类:

class Intersections
{
    protected $arrays;
    private $arraysSize;

    public function __construct($arrays)
    {
        $this->arrays = $arrays;
        $this->arraysSize = count($arrays);
    }

    public function getByThreshold($threshold)
    {
        $intersections = $this->getAll();

        foreach ($intersections as $intersection) {
            if (count($intersection) >= $threshold) {
                return $intersection;
            }
        }   

        return null;
    }

    protected $intersections;
    public function getAll()
    {
        if (is_null($this->intersections)) {
            $this->generateIntersections();
        }

        return $this->intersections;
    }


    private function generateIntersections()
    {
        $this->generateCombinationsMasks();
        $this->generateCombinations();

        $combinationSize = $this->arraysSize;
        $intersectionSize = 0;

        foreach ($this->combinations as $combination) {
            $intersection = call_user_func_array('array_intersect', $combination);

            if ($combinationSize > count($combination)) {
                $combinationSize = count($combination);
                $intersectionSize = 0;
            }

            if (count($intersection) > $intersectionSize) {
                $this->intersections[$combinationSize] = $intersection;
                $intersectionSize = count($intersection);
            }    
        }
    }

    private $combinationsMasks;
    private function generateCombinationsMasks()
    {
        $combinationsMasks = [];
        $totalNumberOfCombinations = pow(2, $this->arraysSize);

        for ($i = $totalNumberOfCombinations - 1; $i > 0; $i--) {
            $combinationsMasks[] = str_pad(
                decbin($i), $this->arraysSize, '0', STR_PAD_LEFT
            );
        }

        usort($combinationsMasks, function ($a, $b) {
            return strcmp(strtr($b, ['']), strtr($a, ['']));
        });

        $this->combinationsMasks = array_slice(
            $combinationsMasks, 0, -$this->arraysSize
        );
    }

    private $combinations;
    private function generateCombinations()
    {
        $this->combinations = array_map(function ($combinationMask) {
            return $this->generateCombination($combinationMask);
        }, $this->combinationsMasks);      
    }

    private function generateCombination($combinationMask)
    {
        $combination = [];
        foreach (str_split($combinationMask) as $key => $indicator) {
            if ($indicator) {
                $combination[] = $this->arrays[$key];
            }
        }

        return $combination;
    }
}
我试图给方法起一个不言自明的名字。一些代码块可以进行更多优化(例如,我在同一数组上多次调用
count
函数;这样做是为了减少变量篡改)以供生产使用

所以基本上逻辑很简单。我们生成数组的所有组合,并按所用数组的数量递减对它们进行排序。然后我们找到每种组合长度的最长交点。实际上,这是最难的部分。为了得到一个特定的交点,我们返回第一个匹配阈值的交点

$intersections = new Intersections([$a, $b, $c, $d]);

var_dump($intersections->getAll());
var_dump($intersections->getByThreshold(3));
这是


还有其他方法可以找到所有组合,例如。您可以选择您最喜欢的任何一个。

内置功能-否。您需要在此处写一点:)阵列的大小是多少?他们有副本吗?你们有多少个阵列?基本上,你应该计算数值并选择那些数值,count>3为什么阈值为3时跳过
$c
?@Federkun我编辑了这篇文章:“阈值意味着我可以从交叉点跳过一个或多个数组,只要生成的交叉点至少有3个元素”最大的交叉点和从交叉点丢弃的阵列数量最少谢谢!这是一个非常优雅的解决方案!编辑:我有点发火了:这不会给我一个元素数组,它至少出现在3个数组中。这不是我对TrHHHOLD的意思,我编辑了这篇文章来反映这一点。我认为实现这一目标的方式更加复杂,因为它们是其他变量来考虑的。比如,如果在不同的数组组合中有相同数量的重复元素,那么要排除哪些元素?@Jelle,请注意,我排除了大小为1的组合(数组与其自身相交),因为这是一个边情况,并且不能将一个参数传递给数组_intersect。所以,你可以自己添加它。您可以实现这样一种方法:将最大长度的
$arrays
中的数组添加到
$crossions
数组的末尾,并使用键
1