My question is a little bit complicated but I will try to explain it as good as I can.
I have an array let's say:
$array(5){
[1]=>1,
[2]=>2,
[3]=>3,
[4]=>4,
[5]=>5
}
And I have a randomly generated key, let's say $rand = 34526147; The length of the key is always the same.
Now the question is: I want to select keys from the array which are ordered randomly BUT BASED ON THE KEY WE HAVE. I mean when I give the same key it will always return the same order but if I change the key it will return differently ordered array. Thank You.
My understanding is you want to shuffle() the array, but make it consistent for whatever $rand value is provided. I also believe PHP uses rand (behind the scenes) within shuffle which makes it possible to use srand (giving a consistent randomized order for the provided key). So, with that said:
$rand = 34526247;
srand($rand);
shuffle($array);
Because you're always seeding random from that same "key" you should get a consistent (repeatable) shuffle outcome. (At least it did with a brief test)
Note: This means $rand must be a numeric value. And, if at any point it isn't, you'd need to convert it to one.
uksort allows defining a custom sort based on the keys:
uksort($array,function($a,$b){
global $rand;
return strpos(''.$rand, ''.$a) - strpos(''.$rand, ''.$b);
});
Note that this assumes all keys exist in $rand.
Example state of array:
Array (
[3] => 3
[4] => 4
[5] => 5
[2] => 2
[1] => 1 )
You should calculate a new value for each question / row in addition to its id. This value needs to change with each new key and look random enough to your players. You can simply multiply the id with the key, then order by the rightmost digits, like this:
$key = 1243;
$questions = array(
195741 => array('foo'),
168762 => array('bar'),
984133 => array('baz'),
);
$newquestions = array();
foreach ($questions as $id => $row) {
// calculate a random looking order depending on $key
$newquestions[$id * $key % 100] = $row;
}
ksort($newquestions);
Output:
Array
(
[19] => Array
(
[0] => baz
)
[63] => Array
(
[0] => foo
)
[66] => Array
(
[0] => bar
)
)
Edit: Include actual sorting
I could be wrong, but I read you to mean that you are asking if you can change the order of the Qs to match that given in the rand int.
$questions = array(
1=>'one',
2=>'two',
3=>'three',
4=>'four',
5=>'five',
);
$rand = 34526147;
$order = array_unique(str_split($rand));
foreach($order as $ord){
if(array_key_exists($ord, $questions)) {
echo 'Q: ' . $ord . ' is ' .$questions[$ord] . PHP_EOL;
}
}
Gives:
Q: 3 is three
Q: 4 is four
Q: 5 is five
Q: 2 is two
Q: 1 is one
Related
I have this type of array,
Array
(
[0] => Array
(
[id] => 0
[fams] => 5
)
[1] => Array --> I want to remove this value using its index, which is "1"
(
[id] => 2
[fams] => 5
)
)
I want to remove that array [1] entirely, using its index, so the condition is - where the ID is match, for example - [id] => 2
Is that possible, to remove a particular value with that specific condition?
and without looping (or any similar method that need to loop the array)
thanks in advance!
FYI - I did try to search around, but, to be honest, I'm not sure what "keyword" do I need to use.
I did try before, but I found, array_search, array_keys - and it seems those 2 are not.
I'm okay, if we need several steps, as long as it did not use "loop" method.
---update
I forgot to mention, that I'm using old PHP 5.3.
array_filter should work fine with PHP 5.3.
The downside of this approach is that array_filter will (internally) iterate over all your array's entries, even after finding the right one (it's not a "short-circuit" approach). But at least, it's quick to write and shouldn't make much of a difference unless you're dealing with very big arrays.
Note: you should definitely upgrade your PHP version anyway!
$array = array (
0 =>
array (
'id' => 0,
'fams' => 5
),
1 =>
array (
'id' => 2,
'fams' => 5
)
);
$indexToRemove = 2;
$resultArray = array_filter($array, function ($entry) use ($indexToRemove) {
return $entry['id'] !== $indexToRemove;
});
Demo: https://3v4l.org/6DXjl
You can use array_search to find the key of a sub-array that has a matching id value (extracted using array_column), and if found, unset that element:
if (($k = array_search(2, array_column($array, 'id'))) !== false) {
unset($array[$k]);
}
print_r($array);
Output:
Array
(
[0] => Array
(
[id] => 0
[fams] => 5
)
)
Demo on 3v4l.org
It should be noted that although there is no explicit loop in this code, array_search and array_column both loop through the array internally.
You can use array_column to make id as index of the sub-array then use unset
$a = array_column($a, null, 'id');//new array id as index
$index = 2;// id to remove
if($a[$index]) unset($a[$index]);
print_r($a);
Working example :- https://3v4l.org/ofMr7
I'm making a program to take fingerprint values using a winnowing algorithm. which is where I have to take the smallest value from an array. but not only the smallest, there are conditions where if you find the same value, the rightmost value will be taken along with the index value. example array (3,5,5,8,6,7). from this example, I want to take the index of the second number 5, which is index 2, not index 1.
but when I try to get the same value as the rightmost position use the function min () in php, but the one I get is always the leftmost position.
I expect the output of
$a = array(3,5,5,8,6,7,6);
be
[3,0], [5,2], [8,3], [6,6], [7,5]
but the actual output is
[3,0], [5,1], [8,3], [6,4], [7,5]
Just a quick alternative, if you use array_flip() which swaps the value and key over, then this will automatically overwrite any previous key value, so when you flip [1=>5, 2=>5] then the second one will overwrite the first.
So
$a = array(3,5,5,8,6,7,6);
print_r(array_flip($a));
gives...
Array
(
[3] => 0
[5] => 2
[8] => 3
[6] => 6
[7] => 5
)
Use the value from an array as an index to filter out the most right value
$values = array(3,5,5,8,6,7,6);
$result = [];
foreach ($values as $index => $value) {
$result[$value] = [$value, $index];
}
print_r(array_values($result));
Use array_unique to solve this problem
$a = array(3,5,5,8,6,7,6);
$unique = array_unique($a);
print_r($unique);
answer should be
Array
(
[0] => 3
[1] => 5
[3] => 8
[4] => 6
[5] => 7
)
I searched many thread but i can't find this solution
I have this Array
Array
( [0] => [1] => Array ( [0] => 2019-01-11T23:30:00CET [1] => -12.6 ) [2] => [3] => Array ( [0] => 2019-01-11T23:20:00CET [1] => -12.5 ) [4] => [5] => Array ( [0] => 2019-01-11T23:10:00CET [1] => -12.6 ) [10] => [11] => Array ( [0] => 2019-01-11T22:40:00CET [1] => -12.4 )
I found the path to have the maximum or minimum value ( Column [1] ) from this Array but i need to find the relative Parent
(example the minimum -12.6 is in the [1][0] as 2019-01-11T22:20:00CET)
of this two values that are show in the first column ( Column[0] )
Thanks
If you use array_column() to extract the second column of your data, then you can use min() or max() with that array to pick which one you want. This code then extracts the ones that match using a foreach() and if to check if it matches (not exactly sure what you want as output, but this should help)...
$source = [["2019-01-11T23:30:00CET", -12.6],
["2019-01-11T23:20:00CET", -12.5],
["2019-01-11T23:10:00CET", -12.6]
];
$extract = min(array_column($source, 1)); // or use max()
$output = [];
foreach ($source as $key => $element) {
if ( $element[1] == $extract ) {
// Matches, so add to output
$output[$key] = $element[0];
}
}
print_r($output);
will give
Array
(
[0] => 2019-01-11T23:30:00CET
[2] => 2019-01-11T23:10:00CET
)
You could use array_filter() to extract the matching rows, but a foreach() is enough for a straightforward thing like this (IMHO).
If there is a possibility of blank values or strings in the value column, this may confuse the min() as it will consider the values and compare them as strings, to ensure they are all compared as numbers you can add...
$values = array_map("floatval", array_column($source, 1));
$extract = min($values); // or use max()
The array_map("floatval",... goes through the list and converts them all to float values.
Also, here's a generalized algorithm-sketch for "finding the max in some array", expressed as pseudo-code:
"Leave quietly" if the array is empty, or throw an exception.
Otherwise, assume that the first element in the array is the biggest one.
Now, loop through the remaining elements, testing if each one is, in fact, bigger than the "biggest one" that you have so far. If so, select it as the "biggest."
When the loop is finished, return your answer.
Now – this is what a geek would call "an O(n) algorithm," which is to say that its execution-time will be "on the order of" the number of elements in the array. Well, if this is a "one-off" requirement, that's fine. Whereas if what you actually want to do is to get "more than one" max-element, sorting the array (once, then holding on to the sorted result ...) becomes significantly better, because the sort is going to be O(log(n)) ... "on the order of some logarithm of the number of elements," ... and the subsequent cost of "popping off" elements from that sorted array becomes non-existent.
There are other ways to do it, of course – trees and such - but I've already blathered-on too long here.
I want to compare every element of array with one another.
$char=array();
for($i=0;$i<=10;$i++)
{
$char[$i]=rand(0,35);
}
I want to compare every element of $char array. If there is any value repeated than it should change value and select another random value which should be unique in array..
In this particular example, where the range of possible values is very small, it would be better to do this another way:
$allPossible = range(0, 35);
shuffle($allPossible);
// Guaranteed exactly 10 unique numbers in the range [0, 35]
$char = array_slice($allPossible, 0, 10);
Or with the equivalent version using array_rand:
$allPossible = range(0, 35);
$char = array_rand(array_flip($allPossible), 10);
If the range of values were larger then this approach would be very wasteful and you should go with checking for uniqueness on each iteration:
$char = array();
for ($i = 0; $i < 10; ++$i) {
$value = null;
// Try random numbers until you find one that does not already exist
while($value === null || in_array($value, $char)) {
$value = rand(0, 35);
}
$char[] = $value;
}
However, this is a probabilistic approach and may take a lot of time to finish depending on what the output of rand happens to be (it's going to be especially bad if the number of values you want is close to the number of all possible values).
Additionally, if the number of values you want to pick is largish (let's say more than 50 or so) then in_array can prove to be a bottleneck. In that case it should be faster to use array keys to check for uniqueness instead of values, since searching for the existence of a key is constant time instead of linear:
$char = array();
for ($i = 0; $i < 100; ++$i) {
$value = null;
// Try random numbers until you find one that does not already exist
while($value === null || array_key_exists($char, $value)) {
$value = rand(0, 1000);
}
$char[$value] = $value;
}
$char = array_values($char); // reindex keys to start from 0
To change any repeated value for a random one, you should loop through the array twice:
$cont= 0;
foreach($char as $c){
foreach($char as $d){
if($c == $d){
//updating the value
$char[$cont] = rand(0,35);
}
}
$cont++;
}
But what I don't know is if the random value can also be repeated. In that case it would not be so simple.
I've taken this code from the PHP Manual page for rand()
<?php
function uniqueRand($n, $min = 0, $max = null)
{
if($max === null)
$max = getrandmax();
$array = range($min, $max);
$return = array();
$keys = array_rand($array, $n);
foreach($keys as $key)
$return[] = $array[$key];
return $return;
}
?>
This function generates an array which has a size of $n and you can set the min and max values like in rand.
So you could make use of it like
uniqueRand(10, 0, 35);
Use array_count_values() first on the $char array.
Afterwards you can just loop all entries with more than 1 and randomize them. You have to keep checking until all counts are 1 tho. As even the random might remake a duplicate again.
I sugggest two option to make random array:
<?php
$questions = array(1, 2, 3, 4, 5, ..., 34, 35);
$questions = shuffle($questions);
?>
after that you choose the top 10 elements.
you can try this code to replace any repeated value.
for ($i = 0; $i < count($char); $i++) {
for ($n = 0; $n < count($char); $n++) {
if($char[$i] == $char[$n]){
$char[$i] = rand(0,35);
}
}
}
The function array_unique() obtains all unique values from an array, keyed by their first occurrence.
The function array_diff() allows to remove values from one array that are inside another array.
Depending on how you need to have (or not have) the result keyed or the order of keys preserved you need to do multiple steps. Generally it works as I outline in the following paragraphs (with PHP code-examples):
In an array you've got N elements of which Nu are unique.
$N = array(...);
$Nu = array_unique($N);
The number of random elements r you need then to replace the duplicates are the count of N minus the count of Nu. As the count of N is generally a useful value, I also assign it to nc:
$nc = count($N);
$r = $nc - count($Nu);
That makes r an integer ranging from 0 to count(N) - 1:
0 : no duplicate values / all values are unique
1 : one duplicate value / all but one value are unique
...
count(N) - 1 : all duplicate values / no unique value
So in case you you need zero random values ($r === 0) the input $N is the result. This boundary condition is the second most simple result (the first simple result is an input array with no members).
For all other cases you need r random unique values. In your question you write from 0 to 35. However this can not be the full story. Imagine your input array has got 36 duplicated values, each number in the range from 0 to 35 is duplicated once. Adding random numbers from the range 0 to 35 again to the array would create duplicates again - guaranteed.
Instead I've read your question that you are just looking for unique values that are not yet part of the input array.
So you not only you need r random values (Nr), but they also must not be part of N or Nu so far.
To achieve that you only need to create count(N) unique values, remove the unique values Nu from these to ensure nothing duplicates values in Nu. As this the theoretical maximum and not the exact number needed, that array is used to obtain the slice of exactly r elements from:
$Nr = array_slice(array_diff(range(0, $nc - 1), $Nu), 0, $r);
If you also want to have these new values to be added shuffled as range(0, $nc - 1) is ordered, you can do the following:
shuffle($Nr);
That should bring the randomness you seem to ask for in your question back into the answer.
That now leaves you with the unique parts of the original array $Nu and r new values in $Nr. Merging both these arrays will give you a result array which ignores key => value relations (the array is re-index):
array_merge($Nu, $Nr);
For example with an exemplary array(3, 4, 2, 1, 4, 0, 5, 0, 3, 5) for $N, the result this gives is:
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
[4] => 0
[5] => 5
[6] => 7
[7] => 9
[8] => 6
[9] => 8
)
As you can see all the unique values (0-5) are at the beginning followed by the new values (6-9). Original keys are not preserved, e.g. the key of value 5 was 6 originally, now it is 5.
The relation or key => value are not retained because of array_merge(), it does re-index number keys. Also next to unique numbers in Nr keys also need to be unique in an array. So for every new number that is added to the unqique existing numbers, a key needs to be used that was a key of a duplicate number. To obtain all keys of duplicate numbers the set of keys in the original array is reduced by the set of keys of all for matches of the duplicate numbers (keys in the "unique array" $Nu):
$Kr = array_keys(array_diff_assoc($N, $Nu));
The existing result $Nr can now be keyed with with these keys. A function in PHP to set all keys for an array is to use the function array_combine():
$Nr = array_combine($Kr, $Nr);
This allows to obtain the result with key => value relations preserved by using the array union operator (+):
$Nu + $Nr;
For example with the $N from the last example, the result this gives is:
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
[5] => 0
[6] => 5
[4] => 8
[7] => 6
[8] => 9
[9] => 7
)
As you can now see for the value 5 it's key 6 has been preserved as well as for the value 0 which had the key 5 in the original array and now as well in the output instead of the key 4 as in the previous example.
However as now the keys have been preserved for the first occurrences of the original values, the order is still changed: First all previously unique values and then all new values. However you might want to add the new values in place. To do that, you need to obtain the order of the original keys for the new values. That can be done by mapping the order by key and the using array_multisort() to sort based on that order.
Because this requires passing return values via parameters, this requires additional, temporary variables which I've chosen to introduce starting with the letter V:
// the original array defines the order of keys:
$orderMap = array_flip(array_keys($N));
// define the sort order for the result with keys preserved
$Vt = $Nu + $Nr;
$order = array();
foreach ($Vt as $key => $value) {
$order[] = $orderMap[$key];
}
Then the sorting is done (here with preserving keys):
// sort an array by the defined order, preserve keys
$Vk = array_keys($Vt);
array_multisort($order, $Vt, $Vk);
The result then is:
array_combine($Vk, $Vt);
Again with the example values from above:
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
[4] => 7
[5] => 0
[6] => 5
[7] => 8
[8] => 6
[9] => 9
)
This example output shows nicely that the keys are ordered from 0 to 9 as they were are well in the input array. Compared with the previous output you can for example see that the first added value 7 (keyed 4) is at the 5th position - same as the value keyed 4 in the original array. The order of the keys have been obtained as well.
If that is the result you strive for you can short-cut the path to this step as well by iterating the original arrays keys and in case each of those keys is not the first value of any duplicate value, you can pop from the new values array instead:
$result = array();
foreach ($N as $key => $value) {
$result[$key] = array_key_exists($key, $Nu) ? $Nu[$key] : array_pop($Nr);
}
Again with the example array values the result (varies from previous because $Nr is shuffled:
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
[4] => 7
[5] => 0
[6] => 5
[7] => 8
[8] => 9
[9] => 6
)
Which in the end might be the simplest way to answer your question. Hope this helps you answering the question. Keep the following in mind:
divide your problem:
you want to know if a value is unqiue or not - array_unique() helps you here.
you want to create X new unique numbers/values. array_diff() helps you here.
align the flow:
obtain unique numbers first.
obtain new numbers first.
use both to process the original array.
Like in this example:
// original array
$array = array(3, 4, 2, 1, 4, 0, 5, 0, 3, 5);
// obtain unique values (1.)
$unique = array_unique($array);
// obtain new unique values (2.)
$new = range(0, count($array) - 1);
$new = array_diff($new, $unique);
shuffle($new);
// process original array (3.)
foreach ($array as $key => &$value) {
if (array_key_exists($key, $unique)) {
continue;
}
$value = array_pop($new);
}
unset($value, $new);
// result in $array:
print_r($array);
Which then (exemplary because of shuffle($new)) outputs:
Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
[4] => 9
[5] => 0
[6] => 5
[7] => 8
[8] => 7
[9] => 6
)
N in this question means any arbitrary number of any size and is not necessarily (but could be) the same. I have an array with N number of key => value pairs. These key => value pairs can also contain another array of size N with N number of key => value pairs. This array can be of N depth, meaning any key => value pair in the array could map to another array.How do I get all the values of this array (storing them in a new, 1 dimensional array), ignoring the keys in the key => value pairs?
array-walk-recursive
rob at yurkowski dot net 26-Oct-2010
06:16
If you don't really particularly
care about the keys of an array, you
can capture all values quite simply:
$sample = array(
'dog' => 'woof',
'cat' => array(
'angry' => 'hiss',
'happy' => 'purr'
),
'aardvark' => 'kssksskss'
);
$output = array();
// Push all $val onto $output.
array_walk_recursive($sample, create_function('$val, $key, $obj', 'array_push($obj, $val);'), &$output);
// Printing echo nl2br(print_r($output, true));
/*
* Array
* (
* [0] => woof
* [1] => hiss
* [2] => purr
* [3] => kssksskss
* )
*/
You could do smt like this:
$output = array();
function genArray( $arr ) {
global $output;
foreach( $arr as $key => $val ) {
if( is_array($val) )
genArray( $val );
else
output[$key] = $val;
}
}
genArray( $myArray );
Instead of recursion, using global variable and function, it could be done via loops, but this is just a general idea, and probably needs a little of your attention, anyway. That should be a good thing :)
There are a ton of solutions in the comments of the array_values php doc.
http://www.php.net/manual/en/function.array-values.php