array_unique and some questions on Zend hash internals
| From: | Stig Venaas | Date: | Sun, 04 Jun 2000 12:13:26 +0000 |
| Subject: | array_unique and some questions on Zend hash internals | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-20175@lists.php.net to get a copy of this message | ||
Hi
I'm implementing a function I've called array_unique that takes an array
(by reference) and removes all duplicate values (the first remains). It
seems to work, but I have a few problems/questions.
Below is the code quoted with | and some comments in between.
|PHP_FUNCTION(array_unique)
|{
| pval **array;
| HashTable *target_hash;
| Bucket **arTmp, **cmpdata, **lastkept;
| Bucket *p;
| int i;
|
| if (ARG_COUNT(ht) != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
| WRONG_PARAM_COUNT;
| }
| target_hash = HASH_OF(*array);
| if (!target_hash) {
| php_error(E_WARNING, "Wrong datatype in array_unique() call");
| return;
| }
|
| if (target_hash->nNumOfElements <= 1) { /* No duplicates */
| RETURN_TRUE;
| }
|
| /* create and sort array with pointers to the target_hash buckets */
| arTmp = (Bucket **) pemalloc((target_hash->nNumOfElements + 1) * sizeof(Bucket *),
target_hash->persistent);
| if (!arTmp) {
| return;
| }
| HANDLE_BLOCK_INTERRUPTIONS(); /* Necessary, and where? */
Do I need to call BLOCK and UNBLOCK? In what situations are they necessary?
Where do I need it?
| for (i = 0, p = target_hash->pListHead; p; i++, p = p->pListNext) {
| arTmp[i] = p;
| }
| arTmp[i] = NULL;
| qsort((void *) arTmp, i, sizeof(Bucket *), array_data_compare);
|
| /* go through the sorted array and remove duplicates as we go */
| lastkept = arTmp;
| for (cmpdata = arTmp + 1; *cmpdata; cmpdata++) {
| if (array_data_compare(lastkept, cmpdata)) {
array_data_compare returns 0 if compare_function fails (one of the
operators being an object or array), this means that array_unique will
remove arrays and objects from the array in most cases. Ideally this
shouldn't happen, is there a better way than using compare_function
directly and duplicate most of the code from array_data_compare? Perhaps
I shouldn't bother, at least I can live with this "feature".
| lastkept = cmpdata;
| } else {
| /* should use zend_hash_apply_deleter() from API */
| my_hash_apply_deleter(target_hash, *cmpdata);
I want to use zend_hash_apply_deleter here, it will be quicker than finding
the bucket from the key, but the deleter function isn't part of the Zend API.
If I am to use it I have to either expose it (you probably don't want any
functions with Bucket arguments in the API), or add a function
zend_hash_unique to the API. Do you see any better way?
| }
| }
|
| HANDLE_UNBLOCK_INTERRUPTIONS(); /* Necessary, and where? */
Is this the right place to unblock?
| RETURN_TRUE;
|}
One last thing, if I have an array indexed by numbers, say
array("a", "a", "b"), array_unique would change it into
array("a", 2 => "b"). Do you think it should be array("a",
"b")?
What is the best way of doing this?
Hope someone can answer at least some of this.
Stig
--
Stig Venaas
UNINETT