用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
。