From: Stig Venaas Date: Sat, 10 Jun 2000 18:58:45 +0000 (+0000) Subject: Adding fuctions array_unique, array_intersect and array_subtract. X-Git-Tag: php-4.0.1RC~289 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=99f151f1bde0483944767cf0ed49d3270f61d326;p=php Adding fuctions array_unique, array_intersect and array_subtract. --- diff --git a/ext/standard/array.c b/ext/standard/array.c index 7819046a51..a4669e52e6 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2142,6 +2142,254 @@ PHP_FUNCTION(array_flip) } /* }}} */ +/* {{{ proto array array_unique(array input) + Removes duplicate values from array */ +PHP_FUNCTION(array_unique) +{ + zval **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_FALSE; + } + + /* copy the argument array */ + *return_value = **array; + zval_copy_ctor(return_value); + + if (target_hash->nNumOfElements <= 1) /* nothing to do */ + return; + + /* 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_FALSE; + 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 delete duplicates from the copy */ + lastkept = arTmp; + for (cmpdata = arTmp + 1; *cmpdata; cmpdata++) { + if (array_data_compare(lastkept, cmpdata)) { + lastkept = cmpdata; + } else { + p = *cmpdata; + if (p->nKeyLength) + zend_hash_del(return_value->value.ht, p->arKey, p->nKeyLength); + else + zend_hash_index_del(return_value->value.ht, p->h); + } + } + pefree(arTmp, target_hash->persistent); +} +/* }}} */ + +/* {{{ proto array array_intersect(array arr1, array arr2 [, ...]) + Returns the entries of arr1 that have values which are present in + all the others arguments */ +PHP_FUNCTION(array_intersect) +{ + zval ***args = NULL; + HashTable *hash; + int argc, i, c = 0; + Bucket ***lists, **list, ***ptrs, *p; + zval *entry; + + /* Get the argument count and check it */ + argc = ARG_COUNT(ht); + if (argc < 2) { + WRONG_PARAM_COUNT; + } + /* Allocate arguments array and get the arguments, checking for errors. */ + args = (zval ***)emalloc(argc * sizeof(zval **)); + if (zend_get_parameters_array_ex(argc, args) == FAILURE) { + efree(args); + WRONG_PARAM_COUNT; + } + array_init(return_value); + /* for each argument, create and sort list with pointers to the hash buckets */ + lists = (Bucket ***)emalloc(argc * sizeof(Bucket **)); + ptrs = (Bucket ***)emalloc(argc * sizeof(Bucket **)); + for (i=0; itype != IS_ARRAY) { + php_error(E_WARNING, "Argument #%d to array_intersect() is not an array", i+1); + argc = i; /* only free up to i-1 */ + goto out; + } + hash = HASH_OF(*args[i]); + list = (Bucket **) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket *), hash->persistent); + if (!list) + RETURN_FALSE; + lists[i] = list; + ptrs[i] = list; + for (p = hash->pListHead; p; p = p->pListNext) + *list++ = p; + *list = NULL; + qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), array_data_compare); + } + /* go through the lists and look for common values */ + while (*ptrs[0]) { + for (i=1; ipData); + entry->refcount++; + if (p->nKeyLength) + zend_hash_update(return_value->value.ht, + p->arKey, p->nKeyLength, + &entry, sizeof(zval *), + NULL); + else + zend_hash_index_update(return_value->value.ht, + p->h, &entry, + sizeof(zval *), + NULL); + if (!*++ptrs[0]) + goto out; + if (array_data_compare(ptrs[0]-1, ptrs[0])) + break; + } + } + } +out: + for (i=0; ipersistent); + } + efree(ptrs); + efree(lists); + efree(args); +} +/* }}} */ + +/* {{{ proto array array_subtract(array arr1, array arr2 [, ...]) + Returns the entries of arr1 that have values which are not present in + any of the others arguments */ +PHP_FUNCTION(array_subtract) +{ + zval ***args = NULL; + HashTable *hash; + int argc, i, c; + Bucket ***lists, **list, ***ptrs, *p; + zval *entry; + + /* Get the argument count and check it */ + argc = ARG_COUNT(ht); + if (argc < 2) { + WRONG_PARAM_COUNT; + } + /* Allocate arguments array and get the arguments, checking for errors. */ + args = (zval ***)emalloc(argc * sizeof(zval **)); + if (zend_get_parameters_array_ex(argc, args) == FAILURE) { + efree(args); + WRONG_PARAM_COUNT; + } + array_init(return_value); + /* for each argument, create and sort list with pointers to the hash buckets */ + lists = (Bucket ***)emalloc(argc * sizeof(Bucket **)); + ptrs = (Bucket ***)emalloc(argc * sizeof(Bucket **)); + for (i=0; itype != IS_ARRAY) { + php_error(E_WARNING, "Argument #%d to array_intersect() is not an array", i+1); + argc = i; /* only free up to i-1 */ + goto out; + } + hash = HASH_OF(*args[i]); + list = (Bucket **) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket *), hash->persistent); + if (!list) + RETURN_FALSE; + lists[i] = list; + ptrs[i] = list; + for (p = hash->pListHead; p; p = p->pListNext) + *list++ = p; + *list = NULL; + qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), array_data_compare); + } + /* go through the lists and look for values of ptr[0] + that are not in the others */ + while (*ptrs[0]) { + c = 1; + for (i=1; ipData); + entry->refcount++; + if (p->nKeyLength) + zend_hash_update(return_value->value.ht, + p->arKey, p->nKeyLength, + &entry, sizeof(zval *), + NULL); + else + zend_hash_index_update(return_value->value.ht, + p->h, &entry, + sizeof(zval *), + NULL); + if (!*++ptrs[0]) + goto out; + if (array_data_compare(ptrs[0]-1, ptrs[0])) + break; + } + } + } +out: + for (i=0; ipersistent); + } + efree(ptrs); + efree(lists); + efree(args); +} +/* }}} */ + int multisort_compare(const void *a, const void *b) { Bucket** ab = *(Bucket ***)a; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index c8dd78d971..5d4baa16a0 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -507,6 +507,10 @@ function_entry basic_functions[] = { PHP_FE(array_pad, NULL) PHP_FE(array_flip, NULL) PHP_FE(array_rand, NULL) + PHP_FE(array_unique, NULL) + PHP_FE(array_intersect, NULL) + PHP_FE(array_subtract, NULL) + /* aliases from array.c */ PHP_FALIAS(pos, current, first_arg_force_ref) PHP_FALIAS(sizeof, count, first_arg_allow_ref) diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h index 38b3174c24..b0d803e9eb 100644 --- a/ext/standard/php_array.h +++ b/ext/standard/php_array.h @@ -69,6 +69,9 @@ PHP_FUNCTION(array_reverse); PHP_FUNCTION(array_pad); PHP_FUNCTION(array_flip); PHP_FUNCTION(array_rand); +PHP_FUNCTION(array_unique); +PHP_FUNCTION(array_intersect); +PHP_FUNCTION(array_subtract); HashTable* php_splice(HashTable *, int, int, zval ***, int, HashTable **); int multisort_compare(const void *a, const void *b);