cant shuffle splfixedarray why so ? what is the possible why to shuffle splfixedarray
<?php
$cfix = new SplFixedArray(5);
$cfix[0]=1;
$cfix[1]=4;
$cfix[2]=2;
$cfix[3]=9;
$cfix[4]=3;
print_r($cfix);
//cant shuffle splfixedarray why so ?
shuffle($cfix);
?>
I needed to shuffle a large fixed array (> 100,000,000 elements) so using the fixed array is necessary for a huge reduction in memory usage compared to an array. A 100,000,000 element array of integers in PHP would require approximately 13.7 GB of memory where SplFixedArray is about 5.3 GB for the same list.
Since casting that large of an SplFixedArray to an array has an unreasonable memory cost (and defeats the purpose of using the fixed array in the first place), I wrote this function to randomize elements in place.
Compared to calling shuffle() on an array, it's only marginally slower (0.48s vs. 0.32s using shuffle on an SplFixedArray vs array of 1,000,000 elements).
/**
* Shuffle implementation for an SplFixedArray. Like PHP's shuffle(array)
* function, this randomizes the elements in the supplied array.
*
* #param \SplFixedArray $array The array to shuffle in place
* #param int $passes Number of passes over each element to randomize
* #return bool true on success
*/
function shuffle_spl_fixed_array(\SplFixedArray &$array, $passes = 1)
{
$size = $array->count();
for ($pass = 0; $pass < $passes; ++$pass) {
for ($idx = 0; $idx < $size; ++$idx) {
$swap = mt_rand(0, $size - 1);
$temp = $array[$swap];
$array[$swap] = $array[$idx];
$array[$idx] = $temp;
}
}
return true;
}
Increase the number of passes of make multiple calls depending on the amount of randomness needed, but I found one pass worked well enough for my purposes, especially if you can then pick from it at random.
It's because shuffle expects an array as parameter.
shuffle() expects parameter 1 to be array, object given..
Workaround using toArray and fromArray:
$cfix = new SplFixedArray(5);
$cfix[0]=1;
$cfix[1]=4;
$cfix[2]=2;
$cfix[3]=9;
$cfix[4]=3;
print_r($cfix);
$array = $cfix->toArray();
shuffle($array);
$cfix = SplFixedArray::fromArray($array);
print_r($cfix);
cant shuffle splfixedarray why so ?
Because $cfix is an object in the form of an array. shuffle() works only on arrays, not on objects. The solution would be to cast the object to an array.
Try like this
<?php
$cfix = new SplFixedArray(5);
$cfix[0]=1; $cfix[1]=4; $cfix[2]=2; $cfix[3]=9; $cfix[4]=3;
$cfix=(array)$cfix; //Casting the $cifx object to an array
shuffle($cfix);
print_r($cfix);
Related
The answers to this question say that unset() doesn't work, but weren't clear on what does. I have a recursive function, which uses static variables, however after the recursion has finished and the value has been returned, I need to reset those variables or subsequent calls (the recursive function is currently been called within a loop) would return wrong values.
In the linked question some people suggested trying $var = NULL outside the function which I did, but to seemingly no effect.
The reason why I used static variables and didn't just write them as parameters to the function is that I don't want a situation where the user can pass in arguments to that function, as the only arguments to the function should be supplied from within it.
My Code
<?
require_once("randX.php"); #"randX()" generates a random floating point number in a specified range.
// require_once("../displayArray.php");
error_reporting(E_ERROR | E_WARNING | E_PARSE);
/*
* Generates a valid, random probability distribution for a given array of elements, that can be used in conjunction with "probSelect()".
* Input:
$arr: An array of elements.
$control: A value that decides how much mass is allowed to be unilaterally dumped onto one element. A high value would permit distributions where most of the mass is concentrated on one element.
If an invalid value is provided, the default is used.
* Output: An associative array where the keys are the elements in the original array, and the values are their probabilities.
* #param array $arr: An array of elements for which the probability distribution would be generated.
* #param float $control: A variable which limits the inequality of the probability distribution.
*/
function probGen(array $arr, float $control = 0.01)
{
$control = ($control <= 1 && $control >= 0)?($control):(0.00001); #Use the default value if an invalid number is supplied.
static $result = []; #Initialises $result with an empty array on first function call.
static $max = 1; #Initialises $max with 1 on first function call.
foreach ($arr as $value)
{
$x = randX(0, $max); #Random probability value.
$result[$value] = ($result[$value] + $x)??0; #Initialise the array with 0 on first call, and on subsequent calls increment by $x to assign probability mass.
$max -= $x; #Ensures that the probability never sums to more than one.
}
/*
* After the execution of the above code, there would be some leftover probability mass.
* The code below adds it to a random element.
*/
$var = array_values($arr);
if($max <= $control) #To limit concentration of most of the probability mass in one variable.
{
$result[$var[rand(0,(count($var)-1))]] += $max; #Selects a random key and adds $max to it.
// print("<br>Sum: ".array_sum($result)."<br>");
return $result;
}
else
{
return probGen($arr, $control);
}
}
$max = NULL;
unset($max);
$result = NULL;
unset($result);
?>
This is always the problem with using static in any circumstances, I would change them to be parameters being passed in and having a default value...
function probGen(array $arr, float $control = 0.01, $result = [], $max = 1 )
(With the appropriate types).
These can then be passed down the chain in your further call...
return probGen($arr, $control, $result, $max);
This allows you better control over what these values start as (you can pass in your own values as a default) as well as being able to reset/adjust them as part of the call.
I'm trying to create a random number generator in PHP. It's supposed to generate three (3) numbers at a time, without repeat. That's to say, the 3 numbers cannot be the same.
Here's what I've tried so far:
$array = [];
$A = mt_rand(1,36);
$array[0] = $A;
$B = mt_rand(1,36);
$array[1] = $B;
if(in_array($B,$array)){
$B = mt_rand(1,36);
$array[1] = $B;
}
$C = mt_rand(1,36);
$array[2] = $C;
if(in_array($C,$array)){
$C = mt_rand(1,36);
$array[2] = $C;
}
$length = count($array);
//display the array values;
for($i = 0; $i < $length; $i++){
echo ($array[$i]."<br>");
}
Can anyone tell me where I'm going wrong?
Like this ( as per my initial comment ),
$array = [];
while( count($array) < 3 ){
$rand = mt_rand(1,36);
$array[$rand] = $rand;
}
print_r( $array );
By setting the "key" to be the random number, we can abuse the fact that associative array keys are unique. Then it's a simple matter of waiting until the array contains the desired amount of unique items.
You can test it here
Outputs: ( your results may vary, it's random )
Array
(
[16] => 16
[20] => 20
[27] => 27
)
UPDATE I was trying to think of a valid way to do it without using a loop ( on my way home from work ), and this way may be even better in some cases.
$a = range(1,36);
shuffle($a);
$array = array_slice($a, 0, 3);
print_r($array);
This will have better performance when the number of items you must find is higher. This is because there is no repetition, no collisions. So if you have a small range but need to find many items for the return, this will preform better. If you have many items and need to return only few, then the first one may be better, if not from speed then from memory use.
You can see it here
For reference this uses
range() - Create an array containing a range of elements.
http://php.net/manual/en/function.range.php
shuffle() - Shuffles (randomizes the order of the elements in) an array. It uses a pseudo random number generator that is not suitable for cryptographic purposes.
http://php.net/manual/en/function.shuffle.php
array_slice() - Returns the sequence of elements from the array as specified by the offset and length parameters.
http://php.net/manual/en/function.array-slice.php
So to explain this last one
First we create an array that contains each of our possible numbers as an element. So for example like this [1,2,3,4,5,6, ...].
Next we shuffle it which randomizes the order of the whole array. Shuffle modifies the array by "reference" so it doesn't return our array and therefor there is no assignment ( I think it returns Boolean, however I'm at a loss as to how it could fail and return false, pretty much it just returns true which we don't want to overwrite our array with ). So our example then becomes this [16,20,27,14,5,1, ...]
Last we cut out the number of items we need to return. Finally we end the example with this [16,20,27];
You can crunch the first one down into one ( really 2) line by assigning the value of the $rand variable in the condition of the loop. Like this:
$array = [];
while( count($array) < 3 && false !== ($rand = mt_rand(1,36))) $array[$rand] = $rand;
Because mt_rand(1,36) will never return boolan false. Also if I remember mt_rand is the same as rand now, or at least in current PHP versions.
Note: As of PHP 7.1.0, rand() uses the same random number generator as mt_rand(). To preserve backwards compatibility rand() allows max to be smaller than min as opposed to returning FALSE as mt_rand(). http://php.net/manual/en/function.rand.php
Hope it helps you, remember to think outside of the box.
Does anyone know what's the randomness of PHP's shuffle() function? Does it depend on the operating system?
Does it use PHP's own seeder?
Is it possible to use mt_rand() as generator?
shuffle() function is based on the same generator as rand(), which is the system generator based on linear congruential algorithm. This is a fast generator, but with more or less randomness. Since PHP 4.2.0, the random generator is seeded automatically, but you can use srand() function to seed it if you want.
mtrand() is based on Mersenne Twister algorithm, which is one of the best pseudo-random algorithms available. To shuffle an array using that generator, you'd need to write you own shuffle function. You can look for example at Fisher-Yates algorithm. Writing you own shuffle function will yield to better randomness, but will be slower than the builtin shuffle function.
Update for PHP 7.1
Since the rng_fixes rfc was implemented for PHP 7.1, the implementation of shuffle now utilizes the Mersenne Twister PRNG (i.e. it uses mt_rand and is affected by calling mt_srand).
The legacy system PRNG (rand) is no longer available; the functions rand and srand are in fact aliased to their mt_ equivalents.
Based on Mirouf's answer (thank you so much for your contribution)... I refined it a little bit to take out redundant array counting. I also named the variables a little differently for my own understanding.
If you want to use this exactly like shuffle(), you could modify the parameter to be passed by reference, i.e. &$array, then make sure you change the return to simply: "return;" and assign the resulting random array back to $array as such:
$array = $randArr; (Before the return).
function mt_shuffle($array) {
$randArr = [];
$arrLength = count($array);
// while my array is not empty I select a random position
while (count($array)) {
//mt_rand returns a random number between two values
$randPos = mt_rand(0, --$arrLength);
$randArr[] = $array[$randPos];
/* If number of remaining elements in the array is the same as the
* random position, take out the item in that position,
* else use the negative offset.
* This will prevent array_splice removing the last item.
*/
array_splice($array, $randPos, ($randPos == $arrLength ? 1 : $randPos - $arrLength));
}
return $randArr;
}
It's random just like rand();
And as PHP style you don't need to seed
mt_rand()
Generates a random number.
shuffle()
Randomizes an array. It also generates new keys in the array rather than just rearranging the old ones.
If you want to seed in PHP you would have used mt_strand().
However, since PHP 4.2.0 seeding is done automatically in PHP when you call mt_rand.
Works with associative and numeric arrays:
function mt_shuffle_array($array) {
$shuffled_array = [];
$arr_length = count($array);
if($arr_length < 2) {
return $array;
}
while($arr_length) {
--$arr_length;
$rand_key = array_keys($array)[mt_rand(0, $arr_length)];
$shuffled_array[$rand_key] = $array[$rand_key];
unset($array[$rand_key]);
}
return $shuffled_array;
}
$array = [-2, -1, 'a' => '1', 'b' => '2', 'c' => '3', 11, 'd' => '4', 22];
$shuffled_array = mt_shuffle_array($array);
I've created a function who sort my array randomly.
/**
* Build a random array
*
* #param mixed $array
*
* #return array
*/
function random_array($array) {
$random_array = array();
// array start by index 0
$countArray = count($array) - 1;
// while my array is not empty I build a random value
while (count($array) != 0) {
//mt_rand return a random number between two value
$randomValue = mt_rand(0, $countArray);
$random_array[] = $array[$randomValue];
// If my count of my tab is 4 and mt_rand give me the last element,
// array_splice will not unset the last item
if(($randomValue + 1) == count($array)) {
array_splice($array, $randomValue, ($randomValue - $countArray + 1));
} else {
array_splice($array, $randomValue, ($randomValue - $countArray));
}
$countArray--;
}
return $random_array;
}
It's not the best way to do that but when I've used the function shuffle, it was always returning a random array in the same order. If this could help someone, I will be happy !
Starting with an array with 10K values. I want to randomly get 1000 values from it and put them into another array.
Right now, I am using a for loop to get the values, but I want to pick 1000 values and not have to loop 1000 times. The array_slice function works, but it doesn't give random values. What is the correct (most efficient) function for this task.
The code right now is
$seedkeys = (...array.....);
for ($i=0; $i<1000; $i++) {
$random = array_rand($seedkeys);
$randseed[$i] = $seedkeys[$random];
}//for close
TIA
Well, there are a few alternatives. I'm not sure which is the fastest since you're dealing with a sizable array, but you may want to try them out:
You can use shuffle, which will randomize the entire array. This will likely have the best performance since you're consuming a significant portion of the array (10%).
shuffle($seedkeys);
$result = array_slice($seedkeys, 0, 1000);
You could use array_rand (as you already said) in the manor that Tom Haigh specifies. This will require copying the keys, so if you're dealing with a significant portion of the source array, this may not be the fastest. (Note the use of array_flip, it's needed to allow the usage of array_intersect_key:
$keys = array_flip(array_rand($seedkeys, 1000));
$result = array_intersect_key($seedkeys, $keys);
If memory is tight, the best solution (besides the MySQL one) would be a loop since it doesn't require arrays to be copied at all. Note that this will be slower, but if the array contains a lot of information, it may offset the slowness by being more memory efficient (since it only ever copies exactly what it returns)...
$result = array();
for ($i = 0; $i < 1000; $i++) {
$result[] = $seedkeys[array_rand($seedkeys)];
}
You could do it in MySQL (assuming that the data for the array starts from MySQL). Be aware this is simple, but not that efficient (See Jan Kneschke's post)...
SELECT * FROM `foo` ORDER BY RAND() LIMIT 1000;
You could use array_rand() to get multiple items ?
$random_keys = array_rand($seedkeys, 1000);
shuffle($random_keys);
This will give you an array of random keys, so to get an array of values you need to do something like this:
$result = array();
foreach ($random_keys as $rand_key) {
$result[] = $seedkeys[$rand_key];
}
You could instead use array_intersect_key():
$result = array_intersect_key($seedkeys, array_flip($random_keys));
What is the best way to generate an MD5 (or any other hash) of a multi-dimensional array?
I could easily write a loop which would traverse through each level of the array, concatenating each value into a string, and simply performing the MD5 on the string.
However, this seems cumbersome at best and I wondered if there was a funky function which would take a multi-dimensional array, and hash it.
(Copy-n-paste-able function at the bottom)
As mentioned prior, the following will work.
md5(serialize($array));
However, it's worth noting that (ironically) json_encode performs noticeably faster:
md5(json_encode($array));
In fact, the speed increase is two-fold here as (1) json_encode alone performs faster than serialize, and (2) json_encode produces a smaller string and therefore less for md5 to handle.
Edit: Here is evidence to support this claim:
<?php //this is the array I'm using -- it's multidimensional.
$array = unserialize('a:6:{i:0;a:0:{}i:1;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:0:{}}}i:2;s:5:"hello";i:3;a:2:{i:0;a:0:{}i:1;a:0:{}}i:4;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:0:{}}}}}}}i:5;a:5:{i:0;a:0:{}i:1;a:4:{i:0;a:0:{}i:1;a:0:{}i:2;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:0:{}}i:3;a:6:{i:0;a:0:{}i:1;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:0:{}}}i:2;s:5:"hello";i:3;a:2:{i:0;a:0:{}i:1;a:0:{}}i:4;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:0:{}}}}}}}i:5;a:5:{i:0;a:0:{}i:1;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:0:{}}}i:2;s:5:"hello";i:3;a:2:{i:0;a:0:{}i:1;a:0:{}}i:4;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:0:{}}}}}}}}}}i:2;s:5:"hello";i:3;a:2:{i:0;a:0:{}i:1;a:0:{}}i:4;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:0:{}}}}}}}}}');
//The serialize test
$b4_s = microtime(1);
for ($i=0;$i<10000;$i++) {
$serial = md5(serialize($array));
}
echo 'serialize() w/ md5() took: '.($sTime = microtime(1)-$b4_s).' sec<br/>';
//The json test
$b4_j = microtime(1);
for ($i=0;$i<10000;$i++) {
$serial = md5(json_encode($array));
}
echo 'json_encode() w/ md5() took: '.($jTime = microtime(1)-$b4_j).' sec<br/><br/>';
echo 'json_encode is <strong>'.( round(($sTime/$jTime)*100,1) ).'%</strong> faster with a difference of <strong>'.($sTime-$jTime).' seconds</strong>';
JSON_ENCODE is consistently over 250% (2.5x) faster (often over 300%) -- this is not a trivial difference. You may see the results of the test with this live script here:
http://nathanbrauer.com/playground/serialize-vs-json.php
http://nathanbrauer.com/playground/plain-text/serialize-vs-json.php
Now, one thing to note is array(1,2,3) will produce a different MD5 as array(3,2,1). If this is NOT what you want. Try the following code:
//Optionally make a copy of the array (if you want to preserve the original order)
$original = $array;
array_multisort($array);
$hash = md5(json_encode($array));
Edit: There's been some question as to whether reversing the order would produce the same results. So, I've done that (correctly) here:
http://nathanbrauer.com/playground/json-vs-serialize.php
http://nathanbrauer.com/playground/plain-text/json-vs-serialize.php
As you can see, the results are exactly the same. Here's the (corrected) test originally created by someone related to Drupal:
http://nathanjbrauer.com/playground/drupal-calculation.php
http://nathanjbrauer.com/playground/plain-text/drupal-calculation.php
And for good measure, here's a function/method you can copy and paste (tested in 5.3.3-1ubuntu9.5):
function array_md5(Array $array) {
//since we're inside a function (which uses a copied array, not
//a referenced array), you shouldn't need to copy the array
array_multisort($array);
return md5(json_encode($array));
}
md5(serialize($array));
I'm joining a very crowded party by answering, but there is an important consideration that none of the extant answers address. The value of json_encode() and serialize() both depend upon the order of elements in the array!
Here are the results of not sorting and sorting the arrays, on two arrays with identical values but added in a different order (code at bottom of post):
serialize()
1c4f1064ab79e4722f41ab5a8141b210
1ad0f2c7e690c8e3cd5c34f7c9b8573a
json_encode()
db7178ba34f9271bfca3a05c5dddf502
c9661c0852c2bd0e26ef7951b4ca9e6f
Sorted serialize()
1c4f1064ab79e4722f41ab5a8141b210
1c4f1064ab79e4722f41ab5a8141b210
Sorted json_encode()
db7178ba34f9271bfca3a05c5dddf502
db7178ba34f9271bfca3a05c5dddf502
Therefore, the two methods that I would recommend to hash an array would be:
// You will need to write your own deep_ksort(), or see
// my example below
md5( serialize(deep_ksort($array)) );
md5( json_encode(deep_ksort($array)) );
The choice of json_encode() or serialize() should be determined by testing on the type of data that you are using. By my own testing on purely textual and numerical data, if the code is not running a tight loop thousands of times then the difference is not even worth benchmarking. I personally use json_encode() for that type of data.
Here is the code used to generate the sorting test above:
$a = array();
$a['aa'] = array( 'aaa'=>'AAA', 'bbb'=>'ooo', 'qqq'=>'fff',);
$a['bb'] = array( 'aaa'=>'BBBB', 'iii'=>'dd',);
$b = array();
$b['aa'] = array( 'aaa'=>'AAA', 'qqq'=>'fff', 'bbb'=>'ooo',);
$b['bb'] = array( 'iii'=>'dd', 'aaa'=>'BBBB',);
echo " serialize()\n";
echo md5(serialize($a))."\n";
echo md5(serialize($b))."\n";
echo "\n json_encode()\n";
echo md5(json_encode($a))."\n";
echo md5(json_encode($b))."\n";
$a = deep_ksort($a);
$b = deep_ksort($b);
echo "\n Sorted serialize()\n";
echo md5(serialize($a))."\n";
echo md5(serialize($b))."\n";
echo "\n Sorted json_encode()\n";
echo md5(json_encode($a))."\n";
echo md5(json_encode($b))."\n";
My quick deep_ksort() implementation, fits this case but check it before using on your own projects:
/*
* Sort an array by keys, and additionall sort its array values by keys
*
* Does not try to sort an object, but does iterate its properties to
* sort arrays in properties
*/
function deep_ksort($input)
{
if ( !is_object($input) && !is_array($input) ) {
return $input;
}
foreach ( $input as $k=>$v ) {
if ( is_object($v) || is_array($v) ) {
$input[$k] = deep_ksort($v);
}
}
if ( is_array($input) ) {
ksort($input);
}
// Do not sort objects
return $input;
}
Answer is highly depends on data types of array values.
For big strings use:
md5(serialize($array));
For short strings and integers use:
md5(json_encode($array));
4 built-in PHP functions can transform array to string:
serialize(), json_encode(), var_export(), print_r().
Notice: json_encode() function slows down while processing associative arrays with strings as values. In this case consider to use serialize() function.
Test results for multi-dimensional array with md5-hashes (32 char) in keys and values:
Test name Repeats Result Performance
serialize 10000 0.761195 sec +0.00%
print_r 10000 1.669689 sec -119.35%
json_encode 10000 1.712214 sec -124.94%
var_export 10000 1.735023 sec -127.93%
Test result for numeric multi-dimensional array:
Test name Repeats Result Performance
json_encode 10000 1.040612 sec +0.00%
var_export 10000 1.753170 sec -68.47%
serialize 10000 1.947791 sec -87.18%
print_r 10000 9.084989 sec -773.04%
Associative array test source.
Numeric array test source.
Aside from Brock's excellent answer (+1), any decent hashing library allows you to update the hash in increments, so you should be able to update with each string sequentially, instead having to build up one giant string.
See: hash_update
md5(serialize($array));
Will work, but the hash will change depending on the order of the array (that might not matter though).
Note that serialize and json_encode act differently when it comes to numeric arrays where the keys don't start at 0, or associative arrays.
json_encode will store such arrays as an Object, so json_decode returns an Object, where unserialize will return an array with exact the same keys.
I think that this could be a good tip:
Class hasharray {
public function array_flat($in,$keys=array(),$out=array()){
foreach($in as $k => $v){
$keys[] = $k;
if(is_array($v)){
$out = $this->array_flat($v,$keys,$out);
}else{
$out[implode("/",$keys)] = $v;
}
array_pop($keys);
}
return $out;
}
public function array_hash($in){
$a = $this->array_flat($in);
ksort($a);
return md5(json_encode($a));
}
}
$h = new hasharray;
echo $h->array_hash($multi_dimensional_array);
Important note about serialize()
I don't recommend to use it as part of hashing function because it can return different result for the following examples. Check the example below:
Simple example:
$a = new \stdClass;
$a->test = 'sample';
$b = new \stdClass;
$b->one = $a;
$b->two = clone $a;
Produces
"O:8:"stdClass":2:{s:3:"one";O:8:"stdClass":1:{s:4:"test";s:6:"sample";}s:3:"two";O:8:"stdClass":1:{s:4:"test";s:6:"sample";}}"
But the following code:
<?php
$a = new \stdClass;
$a->test = 'sample';
$b = new \stdClass;
$b->one = $a;
$b->two = $a;
Output:
"O:8:"stdClass":2:{s:3:"one";O:8:"stdClass":1:{s:4:"test";s:6:"sample";}s:3:"two";r:2;}"
So instead of second object php just create link "r:2;" to the first instance. It's definitely good and correct way to serialize data, but it can lead to the issues with your hashing function.
// Convert nested arrays to a simple array
$array = array();
array_walk_recursive($input, function ($a) use (&$array) {
$array[] = $a;
});
sort($array);
$hash = md5(json_encode($array));
----
These arrays have the same hash:
$arr1 = array(0 => array(1, 2, 3), 1, 2);
$arr2 = array(0 => array(1, 3, 2), 1, 2);
I didn't see the solution so easily above so I wanted to contribute a simpler answer. For me, I was getting the same key until I used ksort (key sort):
Sorted first with Ksort, then performed sha1 on a json_encode:
ksort($array)
$hash = sha1(json_encode($array) //be mindful of UTF8
example:
$arr1 = array( 'dealer' => '100', 'direction' => 'ASC', 'dist' => '500', 'limit' => '1', 'zip' => '10601');
ksort($arr1);
$arr2 = array( 'direction' => 'ASC', 'limit' => '1', 'zip' => '10601', 'dealer' => '100', 'dist' => '5000');
ksort($arr2);
var_dump(sha1(json_encode($arr1)));
var_dump(sha1(json_encode($arr2)));
Output of altered arrays and hashes:
string(40) "502c2cbfbe62e47eb0fe96306ecb2e6c7e6d014c"
string(40) "b3319c58edadab3513832ceeb5d68bfce2fb3983"
there are several answers telling to use json_code,
but json_encode don't work fine with iso-8859-1 string, as soon as there is a special char, the string is cropped.
i would advice to use var_export :
md5(var_export($array, true))
not as slow as serialize, not as bugged as json_encode
Currently the most up-voted answer md5(serialize($array)); doesn't work well with objects.
Consider code:
$a = array(new \stdClass());
$b = array(new \stdClass());
Even though arrays are different (they contain different objects), they have same hash when using md5(serialize($array));. So your hash is useless!
To avoid that problem, you can replace objects with result of spl_object_hash() before serializing. You also should do it recursively if your array has multiple levels.
Code below also sorts arrays by keys, as dotancohen have suggested.
function replaceObjectsWithHashes(array $array)
{
foreach ($array as &$value) {
if (is_array($value)) {
$value = $this->replaceObjectsInArrayWithHashes($value);
} elseif (is_object($value)) {
$value = spl_object_hash($value);
}
}
ksort($array);
return $array;
}
Now you can use md5(serialize(replaceObjectsWithHashes($array))).
(Note that the array in PHP is value type. So replaceObjectsWithHashes function DO NOT change original array.)
in some case maybe it's better to use http_build_query to convert array to string :
md5( http_build_query( $array ) );