Shuffling php array without same value before or after - php

To shuffle an array in php is easy but my problem is when i try to shuffle it without getting the same result before of after that key.
Example:
Array ( 0 => 1, 1 => 2, 2 => 3, 3 => 3 )
I must have a result without 3 coming together.
Example of some array i want:
Array ( 0 => 2, 1 => 3, 2 => 1, 3 => 3 )
I've tryed to check each item of the array, if that happens i shuffle it again, and check another time. But that seems to be waste both on time and process.
EDIT:
Here is the code i use:
do
{
$not_valid=false;
for($i=0;$i<sizeof($arr_times)-1;$i++){
if($arr_times[$i]==$arr_times[$i+1])
$not_valid=true;
}
if($not_valid)
shuffle($arr_times);
}while ($not_valid);

Even though php has really a lot of strange functions - it doesn't have any for described situation.
So you have to do that manually.
PS: also it would be a good idea to check if it's even possible to shuffle input array in an expected way so you wouldn't get into an infinite loop.

From Shuffle list, ensuring that no item remains in same position
<?php
$foo = array(
0,
1,
2,
3,
4,
);
for ($i = 0, $c = sizeof($foo); $i < $c - 1; $i++) {
$new_i = rand($i + 1, $c - 1);
list($foo[$i], $foo[$new_i]) = array($foo[$new_i], $foo[$i]);
}
var_export($foo); // Derangement

Related

I cant figure out this array_map issue I am having

**EDIT:
I am trying to display the number of keys in my arrays that start with a "P", "M" and "D". I think I should be using array_maps and have some luck with it but I am now stuck and tried looking through the manual, on here and w3schools with no luck.
I'm using version 5.6.36 of PHP with XAMPP on a local server. I've tried playing around with array_maps which I think is the right command to use, but I just cant get my head around how to use it properly. I've read the manual on it, looked on here, looked on youtube and W3Schools with no luck. Can anyone help please?
I have this array:
$tasks = array
(
0 => 'P1',
1 => 'M1',
2 => 'D1',
3 => 'P2',
4 => 'D2'
);
I want it to display this:
Array
(
[P] => 2
[M] => 1
[D] => 2
)
See how it returns the number of P's M's and D's nice and neatly?
From what I understand, the solution code should be something like this:
$array2 = array_map(function(???????){
return ??????????;
}, $tasks);
$array2a = (array_count_values($array2));
echo "<pre>"; print_r($array2a); echo "</pre>";
Please help?!
you can use array_map as following :
$tasks = array
(
0 => 'P1',
1 => 'M1',
2 => 'D1',
3 => 'P2',
4 => 'D2'
);
$charsToCheck = array('P','M','D');
$result = array_map(function($v) use ($charsToCheck){
if(in_array(substr( $v, 0, 1),$charsToCheck))
return substr( $v, 0, 1);
}, $tasks);
print_r(array_count_values($result));
Result:-
Array
(
[P] => 2
[M] => 1
[D] => 2
)
The function array_map() creates one output element from every input element. Since you don't want that, it is the wrong tool. Probably the easiest way to achieve your goal is to use a simple loop. However, if things get more complicated, this may not scale well. For those cases, array_reduce() could come in handy:
$input = [
0 => 'P1',
1 => 'M1',
2 => 'D1',
3 => 'P2',
4 => 'D2',
];
$frequency = array_reduce(
$input,
function ($carry, $item) {
$initial = substr($item, 0, 1);
if (array_key_exists($initial, $carry)) {
$carry[$initial] += 1;
}
return $carry;
},
[
'P' => 0,
'M' => 0,
'D' => 0,
]
);
echo json_encode($frequency, JSON_PRETTY_PRINT) . PHP_EOL;
The point of this is that it defines what to do with a single element ($item) and how to modify the resulting state ($carry) in a single function, keeping this part away from the iteration part. Since this avoids mutable state, this can also be seen as a functional (as in "functional programming") approach.
You cannot use array_map for that... You could use reduce I guess but here's a fast and easy way... Basically you create your new array and do the counting according to the first letter of your tasks array.
$list = new Array();
foreach($tasks as $task){
if($list[$task{0}]){
$list[$task{0}]++;
}else{
$list[$task{0}] = 1;
}
}
The problem you'd get with array_map is that it would always produce a 1:1 ratio of your array, which is not what you want...
(sorry for the bad PHP if it is, been ages...)
EDIT:
Using your edited question, here's your possible usage:
$array2 = array_map(function($val){
return $val{0};
}, $tasks);
The key to both answers is the $var{0} part, this extracts the character at index 0...

How to merge arrays in PHP without key preservation?

Am I overlooking a function in PHP that will merge arrays without preserving keys? I've tried both ways of these ways: $arrayA + $arrayB and array_merge($arrayA, $arrayB) but neither are working as I expected.
What I expect is that when I add array(11, 12, 13) and array(1, 2, 3) together that I would end up with array(11, 12, 13, 1, 2, 3).
I created a function of my own which handles it properly, though I was trying to figure out if it was the best way of doing things or if there's an easier or even a build in way that I'm just not seeing:
function array_join($arrayA, $arrayB) {
foreach($arrayB as $B) $arrayA[] = $B;
return $arrayA;
}
Edit:
array_merge() was working as intended, however I had the function running in a loop and I was using the incorrect variable name inside the function, so it was only returning a partial list as is what I was experiencing. For example the loop I was using ended on array(13, 1, 2, 3).
Have you actually tested your code? because array_merge should be enough:
From the documentation of array_merge:
Merges the elements of one or more arrays together so that the values of one are appended to the end of the previous one. (emphasis are mine)
<?php
$a1 = array(11, 12, 13);
$a2 = array(1, 2, 3);
$x = array_merge($a1, $a2);
print_r($x);
It print this on my console:
Array
(
[0] => 11
[1] => 12
[2] => 13
[3] => 1
[4] => 2
[5] => 3
)
$arr1 = array(11, 12, 13);
$arr2 = array(1, 2, 3);
print_r(array_merge($arr1,$arr2));
Try this :
function array_join($arrayA, $arrayB) {
foreach($arrayB as $B) $arrayA[count($arrayA)] = $B;
return $arrayA;
}

Using PHP to randomize 4 weighted items from an array without using the same one twice

I'm creating a php file that displays 4 event sponsor ads. For each sponsor I created an element in an array for their id, name, URL to site, URL for image, level of sponsor, value of sponsorship
I want to create a randomizer that will randomly populate 4 records from the array, but weight the values so that higher level sponsors appear more often than others. I've already created the value for the weight as a percent.
The closest solution I've found to this problem is:
MySQL: Select Random Entry, but Weight Towards Certain Entries
Which suggests including this code, BUT the referenced link for the similar issue doesn't make sense to me. It suggests using ORDER BY -LOG(1.0 – RAND()) / Multiplier but I'm using an array, not record results and I'm not completely clear on how this works...
It looks like array_rand will be helpful to at least generate the 4 different values, but still not sure how to weight them.
You may use a custom function to sort the array based on the weight of sponsor. See usort.
usort($data, function ($value) {
return rand(0, 100 - $value['weight']);
});
Example:
$data = array(
array('name' => 'low', 'weight' => 5),
array('name' => 'medium', 'weight' => 35),
array('name' => 'high', 'weight' => 60)
);
$frequency = array();
for ($i = 0; $i < 1000; $i++) {
usort($data, function ($value) {
return rand(0, 100 - $value['weight']);
});
$head = reset($data);
if (!isset($frequency[$head['name']])) {
$frequency[$head['name']] = 0;
}
$frequency[$head['name']]++;
}
print_r($frequency);
/*
Array
(
[low] => 263
[medium] => 328
[high] => 409
)
*/
This ORDER BY statement will not be executed by your application, it rather tells the DBMS to order the results returned by your query. You add a LIMIT 4 to the query and you're set.
EDIT
Oh, I just read that you do not use a database.
EDIT 2
To really answer your question:
Iterate over your full array
Calculate each item's result using the above equation and store that along with the item's key/index in a temporary array
Sort the temporary array (highest value first), then trim it down to X items
You then have the keys/indexes of X items which were randomly chosen
OK, I finally worked everything out!
Here is how my final code went (I've separated and simplified the code here to piece-meal the tasks):
Create the array
$Sponsors=array(
array('Sponsor' => 'Sponsor1', 'Value' => '500'),
array('Sponsor' => 'Sponsor2', 'Value' => '300'),
array('Sponsor' => 'Sponsor3', 'Value' => '300'),
array('Sponsor' => 'Sponsor4', 'Value' => '200'),)
);
Set SponsorTotalCt = the number of sponsors and create a variable to hold the weighted percentage
$SponsorTotalCt = count($Sponsors);
$SponsorWeight = 0;
Get a total value for all the sponsorships
$SponsorTotalAmt = 0;
foreach($Sponsors as $array)
{
$SponsorTotalAmt += $array['Value'];
};
Add the sponsor weight as a percent as another 'field value' in the $Sponsors array
$i = 0; //initialize i
while ($i < $SponsorTotalCt){
foreach($Sponsors as $array)
{
$SponsorWeight = round($Sponsors[$i]['Value']/$SponsorTotalAmt * 100);
$Sponsors[$i]['Weight'] = $SponsorWeight;
};
$i++; // count one up
};
*Note: at this point the $Sponsors 'record listing' would look kind of like this
$Sponsors =
[0] 'Sponsor1','500', 38 (this last is the percent the sponsorship should be weighted)
[1] 'Sponsor2', '300', 23
[2] 'Sponsor3', '300', 23
[3] 'Sponsor4', '200', 15
Notice that the last set of values adds up to 100, or close to it (because of the rounding)*
Create a new array of 100 'records' where each row of the $Sponsors array is repeated the number of times that reflects the percentage. i.e. Sponsor1 values will be repeated in the array 38 times
$newSponsors = array();
$i = 0; //initialize i
while ($i < $SponsorTotalCt){
foreach($Sponsors as $array)
{
$a = array_fill(0, $Sponsors[$i]['Weight'], $Sponsors[$i]);
};
$newSponsors= array_merge($newSponsors,$a);
$i++; // count one up
};
Finally, randomly select 3 keys from the 4 Sponsors, weighted by the value of their Sponsorships
$spot = array_rand($newSponsors,3);
Now I only have to create the code and call the value. YAY!

Is there a PHP function to count the number of times a value occurs within an array?

I need to count the number of times a value occurs in a given array.
For example:
$array = array(5, 5, 2, 1);
// 5 = 2 times
// 2 = 1 time
// 1 = 1 time
Does such a function exist? If so, please point me to it in the php docs... because I can't seem to find it.
Thanks.
Yes, it's called array_count_values().
$array = array(5, 5, 2, 1);
$counts = array_count_values($array); // Array(5 => 2, 2 => 1, 1 => 1)
array_count_values

Finding the minimum value's key in an associative array

In PHP, say that you have an associative array like this:
$pets = array(
"cats" => 1,
"dogs" => 2,
"fish" => 3
);
How would I find the key with the lowest value? Here, I'd be looking for cats.
Is there some built in PHP function that I've missed which does this? It would also be great if there was a solution that accounted for several values being identical, as below:
$pets = array(
"cats" => 1,
"dogs" => 1,
"fish" => 2
);
Above, I wouldn't mind if it just output either; cats or dogs.
Thanks in advance.
array_keys is your friend:
$pets = array(
"cats" => 1,
"dogs" => 2,
"fish" => 3
);
array_keys($pets, min($pets)); # array('cats')
P.S.: there is a dup here somewhere on SO (it had max instead of min, but I can distinctly remember it).
Thats how i did it.
$pets = array(
"cats" => 1,
"dogs" => 2,
"fish" => 3
);
array_search(min($pets), $pets);
I hope that helps
Might try looking into these:
natcasesort(array)
natsort(array)
$min_val = null;
$min_key = null;
foreach($pets as $pet => $val) {
if ($val < $min_val) {
$min_val = $min;
$min_key = $key;
}
}
You can also flip the array and sort it by key:
$flipped = array_flip($pets);
ksort($flipped);
Then the first key is the minimum, and its value is the key in the original array.
Another approach for retrieving a single string is by using a desirable sorting method and retrieving the first key directly by using key() on the sorted array. In this instance the key with the lowest value is desired, asort will sort from lowest to highest values and reset the internal pointer. To retrieve the reverse (highest to lowest) use arsort.
Example: https://3v4l.org/5ijPh
$pets = array(
"dogs" => 2,
"cats" => 1,
"fish" => 3
);
asort($pets);
var_dump(key($pets));
//string(4) "cats"
$pets = array(
"dogs" => 1,
"cats" => 1,
"fish" => 3
);
asort($pets);
var_dump(key($pets));
//string(4) "dogs"
Take note that all of the PHP array sorting methods will alter the array by-reference.
To prevent altering the original array, create a copy of the array or use an Iterator.
$petsSorted = $pets;
asort($petsSorted);
key($petsSorted);
find the highest value
print max(120, 7, 8, 50);
returns --> 120
$array = array(100, 7, 8, 50, 155, 78);
print max($array);
returns --> 155
find the lowest value
print min(120, 7, 8, 50);
returns --> 7
$array = array(50, 7, 8, 101, 5, 78);
print min($array);
returns --> 5

Categories