Performance analysis
From the operational performance analysis, look at the following test code:
$test =array ();
For ($run =0 $run <10000; $run + +)
$test []=rand (0,100);
$time =microtime (true);
$out = Array_unique ($test);
$time =microtime (True)-$time;
Echo ' Array Unique: '. $time. ' \ n ";
$time =microtime (true);
$out =array_keys (Array_flip ($test));
$time =microtime (True)-$time;
Echo ' Keys Flip: '. $time. ' \ n ";
$time =microtime (true);
$out =array_flip (Array_flip ($test));
$time =microtime (True)-$time;
Echo ' Flip flip: '. $time. \ n ";
The results of the operation are as follows:
As you can see from the figure above, it takes 0.069s to use the Array_unique function, 0.00152s to use the Array_keys function after using Array_flip, and 0.00146s for use with the two-time array_flip function.
The test results show that it is faster to call the Array_keys function after using array_flip than the Array_unique function. So, what is the specific reason? Let's see how these two functions are implemented at the bottom of PHP.
SOURCE Analysis
/* {{{proto array Array_keys (array input [, mixed search_value[, BOOL strict]] return to just the keys from the input AR Ray, optionally only for the specified search_value/php_function (Array_keys) {//variable definition zval *input, * Input array/*search_value = NULL,/* value to search for/* **entry,/* An entry in the input array * /RES,/* Result of comparison */*new_val; /* NEW value */int add_key; /* Flag to indicate whether a key should is added/char *string_key;
/* String key */UINT String_key_len; ULONG Num_key; /* Numeric key */Zend_bool strict = 0;
/* Do strict comparison * * hashposition POS;
Int (*is_equal_func) (Zval *, Zval *, Zval * tsrmls_dc) = is_equal_function; Program parsing parameters if (Zend_parse_parameters (Zend_num_args () tsrmls_cc, "A|zb", &input, &search_value, &strict) = FA
Ilure) {return; //If Strict is true, set Is_equal_func to Is_identical_function, which is congruentCompare if (strict) {is_equal_func = is_identical_function;
*/////if (Search_value!= NULL) {array_init (return_value) The array size returned based on Search_vale initialization;
else {array_init_size (Return_value, zend_hash_num_elements (z_arrval_p (input));
} Add_key = 1; /* traverse the input array parameter, then add the key value to the returned array/zend_hash_internal_pointer_reset_ex (z_arrval_p (input), &pos);//reset pointer//loop traversal array while (Z_arrval_p (input), (void * * *) &entry, &pos) = = SUCCESS) (ZEND_HASH_GET_CURRENT_DATA_EX) {//If Search_value is not an empty if (Search_value!= NULL) {//Determines whether Search_value is the same as the current value and saves the comparison result to the Add_key variable is_eq
Ual_func (&res, Search_value, *entry tsrmls_cc);
Add_key = Zval_is_true (&res);
} if (Add_key) {///Create a ZVAL structure make_std_zval (new_val); Inserts a value into return_value based on whether the key value is a string or integer number switch (zend_hash_get_current_key_ex z_arrval_p (input), &string_key, &s Tring_key_len, &num_key, 1, &pos)) {case Hash_key_is_string:zval_strIngl (New_val, String_key, string_key_len-1, 0); This function is responsible for inserting values into Return_value, and if the key value already exists, the corresponding value is updated with the new value, otherwise it is inserted directly into Zend_hash_next_index_insert (Z_arrval_p (Return_value)
; new_val, sizeof (Zval *), NULL);
Break
Case Hash_key_is_long:z_type_p (new_val) = Is_long;
Z_lval_p (new_val) = Num_key;
Zend_hash_next_index_insert (Z_arrval_p (Return_value), &new_val, sizeof (Zval *), NULL);
Break
}//Move to the next zend_hash_move_forward_ex (z_arrval_p (input), &pos);
}
}
/* }}} */
The
Above is the source code at the bottom of the Array_keys function. To facilitate understanding, the author added some Chinese annotations. If you need to view the original code, you can click to view. The function is to create a new temporary array, and then copy the key-value pairs back to the new array, and replace them with the new values if duplicate key values appear during the copy. The main step of this function is the Zend_hash_next_index_insert function called on the ground 57 and 63 lines. The function inserts an element into an array, and if duplicate values are present, the value pointed to by the original key value is updated with the new value, or inserted directly, with the time complexity of O (n).
/* {{proto array array_flip (array input) return array with key <-> value flipped * * Php_function (Array_flip) {
Define variables Zval *array, **entry, *data;
Char *string_key;
UINT Str_key_len;
ULONG Num_key;
Hashposition POS;
Parse array parameter if (Zend_parse_parameters (Zend_num_args () tsrmls_cc, "a", &array) = = failure) {return;
///Initialize return array array_init_size (Return_value, zend_hash_num_elements (z_arrval_p (array));
Reset Pointer zend_hash_internal_pointer_reset_ex (z_arrval_p (array), &pos); Iterate through each element and perform key <-> value Exchange operations while (ZEND_HASH_GET_CURRENT_DATA_EX z_arrval_p (array), (void * * *) &entry, &pos) =
= SUCCESS) {//initialization of a struct make_std_zval (data); Assigns the value of the original array to the key switch of the new array (ZEND_HASH_GET_CURRENT_KEY_EX z_arrval_p (array), &string_key, &str_key_len, &
Num_key, 1, &pos) {case Hash_key_is_string:zval_stringl (data, String_key, str_key_len-1, 0);
Break Case Hash_key_is_long:z_type_p (DATA) = Is_long;
Z_lval_p (data) = Num_key;
Break ///Assign the key of the original array to the value of the new array, and if there are duplicates, overwrite the old value if (z_type_pp (entry) = = Is_long) {zend_hash_index_update z_arrval_p (r
Eturn_value), Z_LVAL_PP (entry), &data, sizeof (data), NULL); else if (z_type_pp (entry) = = is_string) {zend_symtable_update z_arrval_p (return_value), z_strval_pp (entry), Z_STR
LEN_PP (Entry) + 1, &data, sizeof (data), NULL); else {zval_ptr_dtor (&data);/* would free also zval structure/php_error_docref (NULL tsrmls_cc, E_warn
ING, "Can only flip STRING and INTEGER values!");
}//Next ZEND_HASH_MOVE_FORWARD_EX (z_arrval_p (array), &pos);
}
}
/* }}} */
Above is the Array_flip function of the source code. Click on the link to view the original code. The main thing to do with this function is to create a new array that traverses the original array. At line 26, the value of the original array is assigned to the key of the new array, then the key of the original array is assigned to the value of the new array at line 37, and if there is a duplicate, the old value is overwritten with the new value. The time complexity of the entire function is also O (n). Therefore, the time complexity of using Array_keys after using Array_flip is O (n).
Next, let's look at the source code for the Array_unique function. Click on the link to view the original code.
/* {{proto array array_unique (array input [, int sort_flags]) removes duplicate values from array/php_function (arr
Ay_unique) {//define variable Zval *array, *tmp;
Bucket *p;
struct Bucketindex {Bucket *b;
unsigned int i;
};
struct Bucketindex *artmp, *cmpdata, *lastkept;
unsigned int i;
Long sort_type = php_sort_string; Parse parameter if (Zend_parse_parameters (Zend_num_args () tsrmls_cc, "A|l", &array, &sort_type) = = failure) {return
;
//Set comparison function Php_set_compare_func (Sort_type tsrmls_cc);
Initializes a return array of array_init_size (Return_value, zend_hash_num_elements (z_arrval_p (array)); Copies the value to the new array zend_hash_copy (Z_arrval_p (Return_value), z_arrval_p (array), (copy_ctor_func_t) zval_add_ref, (void *)
&tmp, sizeof (zval*));
if (z_arrval_p (array)->nnumofelements <= 1) {/* do nothing */return; */* Create an array according to the Target_hash buckets pointer and sort/artmp = (struct Bucketindex *) Pemalloc ((z_arrval_p (array)->nnumofelements + 1) * sizeof (struct bucketIndex), z_arrval_p (array)->persistent);
if (!artmp) {zval_dtor (return_value);
Return_false;
for (i = 0, p = z_arrval_p (array)->plisthead; p; i++, p = p->plistnext) {artmp[i].b = P;
ARTMP[I].I = i;
} artmp[i].b = NULL;
Sort zend_qsort (void *) artmp, I, sizeof (struct bucketindex), Php_array_data_compare tsrmls_cc);
/* Traverse sorted array, then delete duplicate elements/lastkept = artmp;
for (Cmpdata = artmp + 1; cmpdata->b; cmpdata++) {if (Php_array_data_compare, lastkept cmpdata)) {
Lastkept = Cmpdata;
} else {if (Lastkept->i > Cmpdata->i) {p = lastkept->b;
Lastkept = Cmpdata;
} else {p = cmpdata->b;
} if (p->nkeylength = = 0) {Zend_hash_index_del (z_arrval_p (return_value), p->h); else {if (z_arrval_p (return_value) = = &eg (symbol_table)) {zend_delete_global_variable (P->arke
Y, p->nkeylength-1 tsrmls_cc);
} else { Zend_hash_quick_del (Z_arrval_p (Return_value), P->arkey, P->nkeylength, p->h);
}}} pefree (Artmp, z_arrval_p (array)->persistent);
}
/* }}} */
As you can see, this function initializes a new array, then copies the value to the new array, and then calls the sort function in 45 rows to sort the arrays, and the sorting algorithm is the Zend engine's block-tree sorting algorithm. The sorted array is then traversed to remove the duplicate elements. The most expensive part of the function is called the sort function, and the time complexity of the fast row is O (Nlogn), so the time complexity of the function is O (NLOGN).
Conclusion
Because the Array_unique bottom calls the fast-scheduling algorithm, it increases the time cost of function running, which results in the slow running of the whole function. That's why Array_keys is faster than the Array_unique function.