如何在不使用PHP中的任何函数的情况下执行此数组过滤?

时间:2017-09-12 22:40:31

标签: php optimization bigdata

假设我有

$a = [1,4,5,8,9,...];

包含大量不连续数字,

$p = [
  1 => [...],
  3 => [...],
  8 => [...],
  10 => [...],
  ...
];

包含已停止索引的数组。

我需要删除$a$p中具有相应索引的所有数字...等待...而不使用任何函数。

有可能吗?如果有,怎么样?如果不是,那么解决这个问题的最佳方式是什么(以挂钟方式)?

2 个答案:

答案 0 :(得分:1)

当然,这是可能的:

$filtered_array = [];
foreach ($a as $index => $value) {
    foreach ($p as $key => $sub_array) {
        if ($key == $value) {
            // this $value of $a corresponds with an existing index in $p, so
            // do NOT add it to our $filtered_array but move on to the next
            // value of $a
            continue 2;
        }
    }
    $filtered_array[$index] = $value;
}

当然这会非常慢,因为$a中的每个条目都不在$p中,您需要遍历整个$p数组才能发现它不是'在那里。更有效的解决方案是利用当您尝试访问不存在的数组索引时抛出的PHP OutOfBoundsException

$filtered_array = [];
foreach ($a as $index => $value) {
    try {
        $p[$value];
    } except (OutOfBoundsException $e) {
        // $value does not exist as an index of $p
        $filtered_array[$index] = $value;
    }
}

如果您不需要保留数组键,性能可能会有所提高(在这种情况下您不需要$index,这会为$a中的每个项目保存内存分配),但我认为这种差异可以忽略不计。

使用某些数组函数更高效:

$filtered_array = [];
foreach ($a as $index => $value) {
    if (!array_key_exists($value, $p)) {
        $filtered_array[$index] = $value;
    }
}

由于您不需要通过PHP错误处理的try / catch机制,因此速度会更快。

如果您允许自己使用unset()删除$p 的值,可能会更快,因此您无需创建新数组但可以改为$a。从您的代码示例和短数组语法,我假设您使用PHP 7.由于PHP 7不再使用foreach的内部数组指针,您可以在迭代时安全地unset()项。如果你在PHP 5上运行,你仍然可以这样做但是你冒着foreach跳过某些项目的风险。

foreach ($a as $index => $value) {
    if (array_key_exists($value, $p)) {
        unset($a[$index]);
    }
}

这样做可以减少第二个(可能很大的)阵列闲置的内存开销。

但是既然你现在已经打破了自己的“无功能”规则,你也可以一直使用array_filter(虽然这不会修改现有的数组,而是构建一个新的数组,这会降低非常大的数组的性能):

$filtered_array = array_filter($a, function($value) use ($p) {
    return !array_key_exists($value, $p);
});

答案 1 :(得分:-2)

所以我回答了我自己的问题,人们太忙了,不能用贬低和幼稚的评论说'#34;它不可能","是它的作业"。不,这不是功课,我只是希望在这里有一点帮助(你知道,就像在社区)。

我试图实现的目标,删除在另一个数组中具有索引的数组中的每个数字(都具有已停止的值)而不使用任何函数

  // temporary $a
  $a_temp = [];

  foreach ($a as $avalue) {
      foreach ($p as $k => $v) {
          // if iterator $a is in the $p (we disregard)
          if ($avalue === $k) {
            continue 2;
          }
      }
      $a_temp[] = $avalue;
  }

  $a = $a_temp;

(如果你看到上述功能,请给我发电子邮件)

这里有一些测试。

/********************************
 * initialize fake data
 ********************************/
$p = [];
for ($i = 0; $i < 10; ++$i) {
    $p[rand(0, 500)] = null;
}

for ($j = 0; $j < 1000; ++$j) {
    $a[rand(0, 500)] = null;
}
$a = array_keys($a);



/********************************
 * first test (without functions)
 ********************************/
$start = microtime(true);

for ($i = 0; $i < 9999; ++$i) {

  $a_temp = [];

  foreach ($a as $avalue) {
      foreach ($p as $k => $v) {

          if ($avalue === $k) {
            continue 2;
          }
      }
      $a_temp[] = $avalue;
  }
}
$firstTestExecTime = (microtime(true) - $start);
// average time : 8s6757750511169



/********************************
 * second test, with functions
 ********************************/
$start = microtime(true);

for ($i = 0; $i < 9999; ++$i) {

    $a_temp = [];

    foreach ($a as $avalue) {

      if (!array_key_exists($avalue, $p)) {
        $a_temp[] = $avalue;
      }
    }

}
$secondTestExecTime = (microtime(true) - $start);
// average time : 5.1003220081329


/********************************
 * printing results
 ********************************/
printf('first test execution time : %s', $firstTestExecTime);
printf('second test execution time : %s', $secondTestExecTime);

有时不建议使用包含大量数据的函数,但在这种情况下,array_search似乎比尝试生成本机代码具有更好的性能。