Nasıl array_diff çalışır?

6 Cevap php

array_diff() nasıl çalışır? Aşağıdaki gibi Açıkçası çalışmıyor olabilir:

function array_diff($arraya, $arrayb)
{
    $diffs = array();
    foreach ($arraya as $keya => $valuea)
    {
        $equaltag = 0;
        foreach ($arrayb as $valueb)     
        {
            if ($valuea == $valueb)
            {
                $equaltag =1;
                break;
            }
        }
        if ($equaltag == o)
        {
              $diffs[$keya]=$valuea;
        }

    }
    return $diffs;                          
}                                  //couldn't be worse than this

Herkes daha iyi bir çözüm biliyor mu?

EDIT @ animuson:

function array_diff($arraya, $arrayb)
{
    foreach ($arraya as $keya => $valuea)
    {
        if (in_array($valuea, $arrayb))
        {
            unset($arraya[$keya]);
        }
    }
    return $arraya;
}

6 Cevap

GÜNCELLEME

  • see below daha hızlı / daha iyi kod için.

  • array_diff davranış php 5.3.4 çok daha iyi olduğunu, ama Leo'nun fonksiyonu dışında hala ~ 10 kat daha yavaş.

  • Ayrıca onlar dizisi tuşları, yani my_array_diff(x,y) == array_values(array_diff(x,y)) kurmayız beri bu fonksiyonlar array_diff kesinlikle eşdeğer olmadığını bilmenizde yarar var.

/ GÜNCELLEME

Daha iyi bir çözüm kullanmak için hash maps

function my_array_diff($a, $b) {
    $map = $out = array();
    foreach($a as $val) $map[$val] = 1;
    foreach($b as $val) if(isset($map[$val])) $map[$val] = 0;
    foreach($map as $val => $ok) if($ok) $out[] = $val;
    return $out;
}

$a = array('A', 'B', 'C', 'D');
$b = array('X', 'C', 'A', 'Y');

print_r(my_array_diff($a, $b)); // B, D

kriter

function your_array_diff($arraya, $arrayb)
{
    foreach ($arraya as $keya => $valuea)
    {
        if (in_array($valuea, $arrayb))
        {
            unset($arraya[$keya]);
        }
    }
    return $arraya;
}

$a = range(1, 10000);
$b = range(5000, 15000);

shuffle($a);
shuffle($b);

$ts = microtime(true);
my_array_diff($a, $b);
printf("ME =%.4f\n", microtime(true) - $ts);

$ts = microtime(true);
your_array_diff($a, $b);
printf("YOU=%.4f\n", microtime(true) - $ts);

sonuç

ME =0.0137
YOU=3.6282

Sorusu olan? ;)

ve, sadece eğlence için,

$ts = microtime(true);
array_diff($a, $b);
printf("PHP=%.4f\n", microtime(true) - $ts);

sonuç

ME =0.0140
YOU=3.6706
PHP=19.5980

Bu inanılmaz!

Hash tabloları üzerinden PHP bunu yapmak için user187291 'ın önerisi sadece harika! Bu harika bir fikir alınan adrenalin acele, ben bile (PHP 5.3.1) biraz daha hızlandırmak için bir yol buldu:

function leo_array_diff($a, $b) {
    $map = $out = array();
    foreach($a as $val) $map[$val] = 1;
    foreach($b as $val) unset($map[$val]);
    return array_keys($map);
}

User187291 en ilanıyla alınan kriter ile:

LEO=0.0322  leo_array_diff()
ME =0.1308  my_array_diff()
YOU=4.5051  your_array_diff()
PHP=45.7114 array_diff()

Array_diff () performans lag bile dizi başına 100 girişlerinde açıktır.

Note: Bu çözelti, ilk dizideki elemanları benzersiz (ya da tek olacaktır) anlamına gelir. Bu, karma bir çözüm için tipiktir.

Note: çözüm endeksleri korumak değildir. $ Haritaya orijinal endeksi atama ve nihayet anahtarları korumak için () array_flip kullanın.

PS: komut iki kez kullanılırsa () hemen hemen aynı görev için üç kez uzun sürdü array_diff: Ben bu iken bazı array_diff () paradoxon arıyor bulundu.

The best solution to know how it works it to take a look at its source-code ;-)
(Well, that's one of the powers of open source -- and if you see some possible optimization, you can submit a patch ;-) )

Array_diff için, içinde ext/standard olmalı - yani, PHP 5.3 için, bu olmalıdır: branches/PHP_5_3/ext/standard

Ve sonra, array.c file looks like a plausible target ; the php_array_diff işlevi, satır 3381, array_diff uygun görünmektedir.


(Good luck going through the code : it's quite long...)

Bu kadar getirdi gibi ne bu böyle bir şey, (BurninLeo cevabı @ bakınız)?

function binary_array_diff($a, $b) {
    $result = $a;
    asort($a);
    asort($b);
    list($bKey, $bVal) = each($b);
    foreach ( $a as $aKey => $aVal ) {
        while ( $aVal > $bVal ) {
            list($bKey, $bVal) = each($b);
        }
        if ( $aVal === $bVal ) {
            unset($result[$aKey]);
        }
    }
    return $result;
}

Bazı testler yapıldıktan sonra, sonuçlar kabul edilebilir gibi görünüyor:

$a = range(1, 10000);
$b = range(5000, 15000);

shuffle($a);
shuffle($b);

$ts = microtime(true);
for ( $n = 0; $n < 10; ++$n ) {
    array_diff($a, $b);
}
printf("PHP    => %.4f\n", microtime(true) - $ts);

$ts = microtime(true);
for ( $n = 0; $n < 10; ++$n ) {
    binary_array_diff($a, $b);
}
printf("binary => %.4f\n", microtime(true) - $ts);

$binaryResult = binary_array_diff($a, $b);
$phpResult    = array_diff($a, $b);
if ( $binaryResult == $phpResult && array_keys($binaryResult) == array_keys($phpResult) ) {
    echo "returned arrays are the same\n";
}

Çıktı:

PHP    => 1.3018
binary => 1.3601
returned arrays are the same

Tabii ki, PHP kodu bu nedenle PHP kodu biraz daha yavaş olduğunu hiç merak var, C kodu kadar iyi yapamıyor.

PHP: "diğer dizilerin hiçbirinde mevcut olmayan tüm dizi1 girdileri içeren bir dizi döndürür."

Yani, sadece array1 Tüm arrayN karşı ve array1 olanların dizilerin herhangi görünmüyor herhangi değerler kontrol edin, yeni bir dizide iade edilecektir.

Sen mutlaka bile array1 'nin tüm değerleri döngü gerekmez. Her değeri ise tüm ek kendi değerleri üzerinden diziler, döngü ve kontrol sadece için in_array($array1, $value).

Bunun yerine unsetting başka bir dizi kullanarak daha iyi bir anlaşma hızlandırabilirsiniz görünüyor. Rağmen, bu kullanım-davasında depeding bir sorunu (I bellek tahsisi gerçek farkları test değil) olabilir daha fazla bellek kullanır.

<?php
function my_array_diff($a, $b) {
  $map = $out = array();
  foreach($a as $val) $map[$val] = 1;
  foreach($b as $val) if(isset($map[$val])) $map[$val] = 0;
  foreach($map as $val => $ok) if($ok) $out[] = $val;
  return $out;
}
function leo_array_diff($a, $b) {
  $map = $out = array();
  foreach($a as $val) $map[$val] = 1;
  foreach($b as $val) unset($map[$val]);
  return array_keys($map);
}
function flip_array_diff_key($b, $a) {
  $at = array_flip($a);
  $bt = array_flip($b);
  $d = array_diff_key($bt, $at);
  return array_keys($d);
}
function flip_isset_diff($b, $a) {
  $at = array_flip($a);
  $d = array();
  foreach ($b as $i)
    if (!isset($at[$i]))
      $d[] = $i;
  return $d;
}
function large_array_diff($b, $a) {
  $at = array();
  foreach ($a as $i)
    $at[$i] = 1;
  $d = array();
  foreach ($b as $i)
    if (!isset($at[$i]))
      $d[] = $i;
  return $d;
}

$functions = array("flip_array_diff_key", "flip_isset_diff", "large_array_diff", "leo_array_diff", "my_array_diff", "array_diff");
#$functions = array_reverse($functions);
$l = range(1, 1000000);
$l2 = range(1, 1000000, 2);

foreach ($functions as $function) {
  $ts = microtime(true);
  for ($i = 0; $i < 10; $i++) {
    $f = $function($l, $l2);
  }
  $te = microtime(true);
  $timing[$function] = $te - $ts;
}
asort($timing);
print_r($timing);

Benim zamanlamaları (PHP 5.3.27-1 ~ dotdeb.0) şunlardır:

[flip_isset_diff] => 3.7415699958801
[flip_array_diff_key] => 4.2989008426666
[large_array_diff] => 4.7882599830627
[flip_flip_isset_diff] => 5.0816700458527
[leo_array_diff] => 11.086831092834
[my_array_diff] => 14.563184976578
[array_diff] => 99.379411935806

Üç yeni fonksiyonlar http://shiplu.mokadd.im/topics/performance-optimization/ bulunmuştur