Heim  >  Artikel  >  Backend-Entwicklung  >  Verwenden Sie array_merge() nicht innerhalb eines Schleifenkörpers

Verwenden Sie array_merge() nicht innerhalb eines Schleifenkörpers

藏色散人
藏色散人nach vorne
2019-10-30 14:02:372746Durchsuche

Der Titel lautet „Array_merge() nicht im Schleifenkörper verwenden“. Tatsächlich ist dies nur eine der Schlussfolgerungen dieses Artikels.

Lassen Sie uns die Zusammenführung von Arrays in der PHP-Sprache untersuchen (rekursive Zusammenführung). wird hier nicht berücksichtigt)

Vergleich von vier Möglichkeiten zum Zusammenführen von Arrays

Vergleich von vier gängigen Möglichkeiten zum Zusammenführen von Arrays

Schreiben von Code

Wir wissen, dass sowohl array_merge() als auch Operator + Arrays verbinden können

Erstellen Sie eine Klasse

ArrayMerge()
● EachOne () Schleifenkörper Verwenden Sie array_merge() zum Zusammenführen
● EachTwo() Nach dem Schleifenkörper verwenden Sie array_merge() zum Zusammenführen
● EachThree() Der Schleifenkörper ist verschachtelt, um die Array-Zusammenführung zu implementieren
● EachFour( ) Der Schleifenkörper verwendet Operator + Spleißen und Zusammenführen
● getNiceFileSize() konvertiert die Speichernutzung in ein für Menschen lesbares Format

/**
 * Class ArrayMerge
 */
class ArrayMerge
{
    /**
     * @param int $times
     * @return array
     */
    public static function eachOne(int $times): array
    {
        $a = [];
        $b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        for ($i = 0; $i < $times; $i++) {
            $a = array_merge($a, $b);
        }
        return $a;
    }
    /**
     * @param int $times
     * @return array
     */
    public static function eachTwo(int $times): array
    {
        $a = [[]];
        $b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        for ($i = 0; $i < $times; $i++) {
            $a[] = $b;
        }
        return array_merge(...$a);
    }
    /**
     * @param int $times
     * @return array
     */
    public static function eachThree(int $times): array
    {
        $a = [];
        $b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        for ($i = 0; $i < $times; $i++) {
            foreach ($b as $item) {
                $a[] = $item;
            }
        }
        return $a;
    }
    /**
     * @param int $times
     * @return array
     */
    public static function eachFour(int $times): array
    {
        $a = [];
        $b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        for ($i = 0; $i < $times; $i++) {
            $a = $b + $a;
        }
        return $a;
    }
    /**
     * 转化内存信息
     * @param      $bytes
     * @param bool $binaryPrefix
     * @return string
     */
    public static function getNiceFileSize(int $bytes, $binaryPrefix = true): ?string
    {
        if ($binaryPrefix) {
            $unit = array(&#39;B&#39;, &#39;KiB&#39;, &#39;MiB&#39;, &#39;GiB&#39;, &#39;TiB&#39;, &#39;PiB&#39;);
            if ($bytes === 0) {
                return &#39;0 &#39; . $unit[0];
            }
            return @round($bytes / (1024 ** ($i = floor(log($bytes, 1024)))),
                    2) . &#39; &#39; . ($unit[(int)$i] ?? &#39;B&#39;);
        }
        $unit = array(&#39;B&#39;, &#39;KB&#39;, &#39;MB&#39;, &#39;GB&#39;, &#39;TB&#39;, &#39;PB&#39;);
        if ($bytes === 0) {
            return &#39;0 &#39; . $unit[0];
        }
        return @round($bytes / (1000 ** ($i = floor(log($bytes, 1000)))),
                2) . &#39; &#39; . ($unit[(int)$i] ?? &#39;B&#39;);
    }
}

Verwenden Sie

, um mehr zuzuweisen Speicher zuerst

Speicher ausgeben Belegen und führen Sie die Array-Länge zusammen und zeichnen Sie die Zeit jedes Schritts auf

ini_set(&#39;memory_limit&#39;, &#39;4000M&#39;);
$timeOne = microtime(true);
$a       = ArrayMerge::eachOne(10000);
echo &#39;count eachOne Result | &#39; . count($a) . PHP_EOL;
echo &#39;memory eachOne Result | &#39; . ArrayMerge::getNiceFileSize(memory_get_usage(true)) . PHP_EOL;
$timeTwo = microtime(true);
$b       = ArrayMerge::eachTwo(10000);
echo &#39;count eachTwo Result | &#39; . count($b) . PHP_EOL;
echo &#39;memory eachTwo Result | &#39; . ArrayMerge::getNiceFileSize(memory_get_usage(true)) . PHP_EOL;
$timeThree = microtime(true);
$c         = ArrayMerge::eachThree(10000);
echo &#39;count eachThree Result | &#39; . count($c) . PHP_EOL;
echo &#39;memory eachThree Result | &#39; . ArrayMerge::getNiceFileSize(memory_get_usage(true)) . PHP_EOL;
$timeFour = microtime(true);
$d        = ArrayMerge::eachFour(10000);
echo &#39;count eachFour Result | &#39; . count($d) . PHP_EOL;
echo &#39;memory eachFour Result | &#39; . ArrayMerge::getNiceFileSize(memory_get_usage(true)) . PHP_EOL;
$timeFive = microtime(true);
echo PHP_EOL;
echo &#39;eachOne | &#39; . ($timeTwo - $timeOne) . PHP_EOL;
echo &#39;eachTwo | &#39; . ($timeThree - $timeTwo) . PHP_EOL;
echo &#39;eachThree | &#39; . ($timeFour - $timeThree) . PHP_EOL;
echo &#39;eachFour | &#39; . ($timeFive - $timeFour) . PHP_EOL;
echo PHP_EOL;

Ergebnis

count eachOne Result | 100000
memory eachOne Result | 9 MiB
count eachTwo Result | 100000
memory eachTwo Result | 14 MiB
count eachThree Result | 100000
memory eachThree Result | 18 MiB
count eachFour Result | 10           #注意这里
memory eachFour Result | 18 MiB
eachOne | 5.21253490448                 # 循环体中使用array_merge()最慢,而且耗费内存
eachTwo | 0.0071840286254883            # 循环体结束后使用array_merge()最快
eachThree | 0.037622928619385           # 循环体嵌套比循环体结束后使用array_merge()慢三倍
eachFour | 0.0072360038757324           # 看似也很快,但是合并的结果有问题

● Verwenden von array_merge () im Schleifenkörper ist am langsamsten und verbraucht Speicher

● Die Verwendung von array_merge() nach dem Ende des Schleifenkörpers ist am schnellsten

● Die Verschachtelung des Schleifenkörpers ist dreimal langsamer als die Verwendung von array_merge() nach dem Schleifenkörper endet

● Es scheint sehr schnell zu sein, aber es gibt ein Problem mit dem zusammengeführten Ergebnis

Die Fallstricke beim Zusammenführen von Arrays

Das ist uns aufgefallen Die Ergebnislänge von everyFour beträgt derzeit nur 10

Lassen Sie uns untersuchen, warum Es wird ein Ergebnis wie dieses geben

Hier sind die rekursiven Zusammenführungen zum Vergleich

Code

public static function test(): void
{
    $testA = [
        &#39;111&#39; => &#39;testA1&#39;,
        &#39;abc&#39; => &#39;testA1&#39;,
        &#39;222&#39; => &#39;testA2&#39;,
    ];
    $testB = [
        &#39;111&#39; => &#39;testB1&#39;,
        &#39;abc&#39; => &#39;testB1&#39;,
        &#39;222&#39; => &#39;testB2&#39;,
        &#39;www&#39; => &#39;testB1&#39;,
    ];
    echo &#39;array_merge($testA, $testB) | &#39; . PHP_EOL;
    print_r(array_merge($testA, $testB));
    echo &#39;$testA + $testB | &#39; . PHP_EOL;
    print_r($testA + $testB);
    echo &#39;$testB + $testA | &#39; . PHP_EOL;
    print_r($testB + $testA);
    echo &#39;array_merge_recursive($testA, $testB) | &#39; . PHP_EOL;
    print_r(array_merge_recursive($testA, $testB));
}

Ergebnis

+-Zeichen wird verwendet, um zwei Arrays zu verbinden. Letzteres ergänzt nur die Schlüssel, die ersteres nicht hat, behält aber die numerischen Werte bei index.

array_merge() und array_merge_recursive() löschen den numerischen Index und alle numerischen Indizes werden in der Reihenfolge von 0 gestartet

array_merge($testA, $testB) |    #数字索引强制从0开始了 字符key相同的以后者为准
Array
(
    [0] => testA1
    [abc] => testB1
    [1] => testA2
    [2] => testB1
    [3] => testB2
    [www] => testB1
)
$testA + $testB |        #testA得到保留,testB补充了testA中没有的key,数字索引得到保留
Array
(
    [111] => testA1
    [abc] => testA1
    [222] => testA2
    [www] => testB1
)
$testB + $testA |        #testB得到保留,testA补充了testB中没有的key,数字索引得到保留
Array
(
    [111] => testB1
    [abc] => testB1
    [222] => testB2
    [www] => testB1
)

array_merge_recursive($testA, $

Array
(
    [0] => testA1
    [abc] => Array
        (
            [0] => testA1
            [1] => testB1
        )
    [1] => testA2
    [2] => testB1
    [3] => testB2
    [www] => testB1
)
)

Analyse

Wenn Sie das sehen, müssen Sie sehr verwirrt sein. Ich habe nicht erwartet, dass array_merge() solche Fallstricke hat

Werfen wir einen Blick auf die offizielle erstes Handbuch

array_merge ( array $array1 [, array $... ] ) : array

array_merge () Führt die Zellen eines oder mehrerer Arrays zusammen, wobei die Werte in einem Array an das vorherige Array angehängt werden. Gibt das resultierende Array zurück.

Wenn das Eingabearray denselben Zeichenfolgenschlüsselnamen hat, überschreibt der Wert nach dem Schlüsselnamen den vorherigen Wert. Wenn das Array jedoch numerische Schlüssel enthält, überschreiben die nachfolgenden Werte nicht die ursprünglichen Werte, sondern werden an diese angehängt.

Wenn nur ein Array angegeben ist und das Array numerisch indiziert ist, werden die Schlüsselnamen fortlaufend neu indiziert.

Nur ​​wenn der String-Schlüsselname derselbe ist, überschreibt der nachfolgende Wert den vorherigen Wert. (Das Handbuch erklärt aber nicht, warum der Index des numerischen Tastennamens zurückgesetzt wird)

Dann werfen wir einen Blick auf den Quellcode

PHPAPI int php_array_merge(HashTable *dest, HashTable *src)
{
    zval *src_entry;
    zend_string *string_key;
    if ((dest->u.flags & HASH_FLAG_PACKED) && (src->u.flags & HASH_FLAG_PACKED)) {
        // 自然数组的合并,HASH_FLAG_PACKED表示数组是自然数组([0,1,2])   参考http://ju.outofmemory.cn/entry/197064
        zend_hash_extend(dest, zend_hash_num_elements(dest) + zend_hash_num_elements(src), 1);
        ZEND_HASH_FILL_PACKED(dest) {
            ZEND_HASH_FOREACH_VAL(src, src_entry) {
                if (UNEXPECTED(Z_ISREF_P(src_entry)) &&
                    UNEXPECTED(Z_REFCOUNT_P(src_entry) == 1)) {
                    ZVAL_UNREF(src_entry);
                }
                Z_TRY_ADDREF_P(src_entry);
                ZEND_HASH_FILL_ADD(src_entry);
            } ZEND_HASH_FOREACH_END();
        } ZEND_HASH_FILL_END();
    } else {
        //遍历获取key和vaule
        ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
            if (UNEXPECTED(Z_ISREF_P(src_entry) &&
                Z_REFCOUNT_P(src_entry) == 1)) {
                ZVAL_UNREF(src_entry);
            }
            Z_TRY_ADDREF_P(src_entry);
            //  参考https://github.com/pangudashu/php7-internal/blob/master/7/var.md
            if (string_key) {
                // 字符串key(zend_string)  插入或者更新元素,会增加key的计数
                zend_hash_update(dest, string_key, src_entry);
            } else {
                //插入新元素,使用自动的索引值(破案了,索引被重置的原因在此)
                zend_hash_next_index_insert_new(dest, src_entry);
            }
        } ZEND_HASH_FOREACH_END();
    }
    return 1;
}

Zusammenfassung

Zusammenfassung Wie oben erwähnt weisen verschiedene Methoden zum Zusammenführen von Arrays bestimmte Mängel auf, aber durch unsere obige Untersuchung haben wir gelernt, dass

● Es nicht ratsam ist, array_merge() im Schleifenkörper zu verwenden, um Arrays zusammenzuführen. und der Geschwindigkeitsunterschied beträgt bis zu hundertmal

● array_merge() sollte beim Zusammenführen von Arrays mit Vorsicht verwendet werden. Wenn der Schlüssel wichtig ist und es sich möglicherweise um eine Zahl handelt, kann array_merge() nicht zum Zusammenführen verwendet werden . Wir können verschachtelte Schleifenkörper verwenden (beachten Sie, dass die innere Schleife den Schlüssel für die Zuweisung verwendet)

● Wenn der Schlüssel wichtig ist und der Schlüssel eine Zahl sein kann, kann Operator + verwendet werden, um Arrays einfach zusammenzuführen Es darf nicht im Schleifenkörper verwendet werden, da das Ergebnis jeder Operation darin besteht, ein neues Array von

zu generieren

Das obige ist der detaillierte Inhalt vonVerwenden Sie array_merge() nicht innerhalb eines Schleifenkörpers. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:learnku.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen