add `shuffle()` and `shuffled()`

This commit is contained in:
CismonX 2018-08-13 19:35:34 +08:00
parent 8ca9980472
commit bf4eaca339
5 changed files with 78 additions and 3 deletions

View File

@ -198,6 +198,7 @@ const zend_function_entry collection_methods[] = {
PHP_ME(Collection, reverse, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Collection, reversed, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Collection, shuffle, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Collection, shuffled, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Collection, set, key_value_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, single, predicate_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, slice, keys_arginfo, ZEND_ACC_PUBLIC)

View File

@ -5,6 +5,7 @@
//
#include <php.h>
#include <ext/standard/php_mt_rand.h>
#include "php_collections.h"
#include "php_collections_me.h"
@ -1479,7 +1480,40 @@ PHP_METHOD(Collection, reversed)
PHP_METHOD(Collection, shuffle)
{
zend_array* current = COLLECTION_FETCH_CURRENT();
uint32_t num_elements = zend_hash_num_elements(current);
ARRAY_NEW(shuffled, num_elements);
ZEND_HASH_FOREACH_VAL(current, zval* val)
zend_hash_next_index_insert(shuffled, val);
ZEND_HASH_FOREACH_END();
size_t offset = 0;
Bucket* bucket = shuffled->arData;
for (; offset < num_elements - 1; ++offset) {
zend_long rand_idx = php_mt_rand_range(offset, num_elements - 1);
zend_hash_bucket_renum_swap(&bucket[offset], &bucket[rand_idx]);
}
if (GC_REFCOUNT(current) > 1)
GC_DELREF(current);
else
zend_hash_destroy(current);
COLLECTION_FETCH_CURRENT() = shuffled;
}
PHP_METHOD(Collection, shuffled)
{
zend_array* current = COLLECTION_FETCH_CURRENT();
uint32_t num_elements = zend_hash_num_elements(current);
ARRAY_NEW(shuffled, num_elements);
ZEND_HASH_FOREACH_VAL(current, zval* val)
zend_hash_next_index_insert(shuffled, val);
ZEND_HASH_FOREACH_END();
size_t offset = 0;
Bucket* bucket = shuffled->arData;
for (; offset < num_elements - 1; ++offset) {
zend_long rand_idx = php_mt_rand_range(offset, num_elements - 1);
zend_hash_bucket_renum_swap(&bucket[offset], &bucket[rand_idx]);
}
RETVAL_NEW_COLLECTION(shuffled);
}
PHP_METHOD(Collection, set)

View File

@ -84,6 +84,7 @@ PHP_METHOD(Collection, retainAll);
PHP_METHOD(Collection, reverse);
PHP_METHOD(Collection, reversed);
PHP_METHOD(Collection, shuffle);
PHP_METHOD(Collection, shuffled);
PHP_METHOD(Collection, set);
PHP_METHOD(Collection, single);
PHP_METHOD(Collection, slice);

View File

@ -695,11 +695,18 @@ class Collection implements ArrayAccess, Countable
function set($key, $value) {}
/**
* Randomly shuffles elements in this collection.
* Randomly shuffles elements in this collection. Keys will be discarded.
*
* @return void
*/
function shuffle() {}
/**
* Returns a shuffled copy of this collection. Keys will be discarded.
*
* @return Collection
*/
function shuffle() {}
function shuffled() {}
/**
* Returns the single element matching the given predicate, or null if there is no or more than

View File

@ -0,0 +1,32 @@
--TEST--
Test Collection::shuffle() and Collection::shuffled().
--FILE--
<?php
$array = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5];
for ($i = 0; ; ++$i) {
$collection = Collection::init($array);
$collection->shuffle();
if ($collection != array_values($array))
break;
if ($i > 10) {
echo 'Collection::shuffle() failed.', PHP_EOL;
exit;
}
}
if (array_sum($array) != array_sum($collection->toArray()))
echo 'Collection::shuffle() failed.', PHP_EOL;
for ($i = 0; ; ++$i) {
$reversed = Collection::init($array)->shuffled();
if ($reversed != array_values($array))
break;
if ($i > 10) {
echo 'Collection::shuffled() failed.', PHP_EOL;
exit;
}
}
if (array_sum($array) != array_sum($reversed->toArray()))
echo 'Collection::shuffled() failed.', PHP_EOL;
?>
--EXPECT--