I am looking to figure out how to use a database of sales completions to influence split testing.
For example, say I have four different page layouts and for each I have the following stats:
Version 1: 6 sales,
Version 2: 1 sale,
Version 3: 3 sales,
Version 4: 4 sales,
Then it would make sense to have version 1 shown most often, and version 4 being next, while version 2 should hardly be shown at all.
Any ideas how I can achieve this?
Very simple solution, mainly depends on how your data looks currently as to what solution is easiest though.
$sales = array
(
1 => 6,
2 => 1,
3 => 3,
4 => 4
);
$weight = array();
foreach ($sales AS $layout => $num_sales)
{
for ($i = 0; $i < $num_sales; $i++)
{
$weight[] = $layout;
}
}
/*
$weight = array
(
1, 1, 1, 1, 1, 1,
2,
3, 3, 3,
4, 4, 4, 4
);
*/
// Pick a random one to use
$layout_to_use = $weight[rand(0, count($weight))];
Let's say you have display the layouts with following weights:
Version 1: 6
Version 4: 4
Version 3: 3
Version 2: 1
Sum of weight is 14 and weight 6 means that you want to show page approximately 6 times in 14 requests.
If you were using database (which I assume you do it would be)
SELECT SUM(weights) FROM version;
Easiest way to implement random selection with different probabilities of hitting item is to sum weights, sort items by their weights and than just iterate trough all items until you hit zero:
$i = rand( 1, $sum);
foreach( $items as $item){
$i -= $item->weight;
if( $i <= 0){
break;
}
}
// $item is now your desired $item
$items should be sorted list of class Item{ public $weight; ... }, because it's most probable that the first element will be used (second the second and so on) and least iterations will be required
What's happening inside:
$i = 12;
// first iteration, $weight = 6
$i = 6; // condition didn't match
// second iteration, $weight = 4
$i = 2; // condition didn't match
// third iteration, $weight = 3
$i = -1; // condition matched
// using version 3
Related
Pair every two arrays is the task – store it, print it and repeat it until it becomes one value.
input : 1, 2, 3, 4, 5, 6, 8, 9, 9
output: 3 7 11 17 9
10 28 9
38 9
47
My code is working fine in this scenario. Somehow I managed to add 0 at the end for pairless elements. But my main focus is how can I make the logic even more clearer to avoid grumpy offset errors?.
My code:
function sumForTwos($arr)
{
if(count($arr) == 1){
exit;
}
else {
$sum = [];
for ($i = 0; $i < count($arr) -1; $i++)
{
//logic to add last array for odd count to avoid offset error
if(count($arr) % 2 == 1){ $arr[count($arr)] = 0; }
//logic to pair arrays
if($i != 0) { $i++; }
$sum = $arr[$i] + $arr[$i + 1];
$total[] = $sum;
echo $sum . " ";
}
echo "<br>";
$arr = $total;
//Recursion function
sumForTwos($arr);
}
}
sumForTwos([1, 2, 3, 4, 5, 6, 8, 9, 9]);
You can adopt an iterative approach and look at this as processing each level of values with every next level have 1 value less from total values. In other words, you can look at this as a breadth first search going level by level. Hence, you can use a queue data structure processing each level one at a time.
You can use PHP's SplQueue class to implement this. Note that we can advantage of this class as it acts as a double-ended queue with the help of below 4 operations:
enqueue - Enqueues value at the end of the queue.
dequeue - Dequeues value from the top of the queue.
push - Pushes value at the end of the doubly linked list(here, queue is implemented as doubly linked list).
pop - Pops a node from the end of the doubly linked list.
Most certainly, all the above 4 operations can be done in O(1) time.
Algorithm:
Add all array elements to queue.
We will loop till the queue size is greater than 1.
Now, if queue level size is odd, pop the last one and keep it in buffer(in a variable).
Add all pairwise elements by dequeueing 2 at a time and enqueue their addition for next level.
After level iteration, add the last element back if the previous level size was odd.
Print those added elements and echo new lines for each level accordingly.
Snippet:
<?php
function sumForTwos($arr){
if(count($arr) == 1){
echo $arr[0];
return;
}
$queue = new SplQueue();
foreach($arr as $val){
$queue->enqueue($val); // add elements to queue
}
while($queue->count() > 1){
$size = $queue->count();
$last = false;
if($size % 2 == 1){
$last = $queue->pop(); // pop the last odd element from the queue to make queue size even
$size--;
}
for($i = 0; $i < $size; $i += 2){
$first = $queue->dequeue();
$second = $queue->dequeue();
echo $first + $second," ";
$queue->enqueue($first + $second);
}
if($last !== false){// again add the last odd one out element if it exists
echo $last; // echo it too
$queue->push($last);
}
echo PHP_EOL;// new line
}
}
sumForTwos([1, 2, 3, 4, 5, 6, 8, 9, 9]);
Demo: http://sandbox.onlinephpfunctions.com/code/5b9f6d4c9291693ac7cf204af42d1f0ed852bdf9
Does this do what you want?
function pairBySums($inputArray)
{
if (sizeof($inputArray) % 2 == 1) {
$lastEntry = array_pop($inputArray); //$inputArray now has even number of elements
}
$answer = [];
for ($ii = 0; $ii < sizeof($inputArray) / 2; $ii++) {
$firstIndexOfPair = $ii * 2; // 0 maps to 0, 1 maps to 2, 3 maps to 4 etc
$secondIndexOfPair = $firstIndexOfPair + 1; // 0 maps to 1, 1 maps to 3, 2 maps to 5 etc
$answer[$ii] = $inputArray[$firstIndexOfPair] + $inputArray[$secondIndexOfPair];
}
if (isset($lastEntry)) {
array_push($answer, $lastEntry);
}
echo implode(' ', $answer) . "<br>";
if (sizeof($answer) > 1) {
pairBySums($answer);
}
}
The algorithm makes sure it operates on an even array and then appends the odd entry back on the array if there is one.
$input = [1, 2, 3, 4, 5, 6, 8, 9, 9];
pairBySums($input);
produces:
3 7 11 17 9
10 28 9
38 9
47
With an even number of items,
$input = [1, 2, 3, 4, 5, 6, 8, 9];
pairBySums($input);
produces:
3 7 11 17
10 28
38
I am working on a scratch card in PHP and i need to build the backbone behind it.
My plan is as following:
Generate 15 random numbers ( there are 8 containers and 15 images to choose from. ).
Each number correspondences with a image ( 1 is image 1, 2 is image 2 etc. ).
Show a random image (1/15) on container 1, show random image (1/15) on container 2 etc. There are 8 containers to be filled.
What i currently can't figure out is to check if there are duplicate numbers, and if so it is fine to have 2 duplicates but not 3 since that would mean a win.
What i have now is this:
$images = array();
for ($i = 0; $i < 8; $i++) {
$random[$i] = rand(1,15);
}
This will fill $random with 15 numbers i can use. Now i want to check if within those 15 there are duplicates. But the trick is that duplicates are no problem ( and even preferred on some degree ) but once there are 3 of the same numbers i want one of those to change again in a random number ( and re-check for duplicates).
So what should be fine ( 2x 8 is fine, 2x 1 is fine ):
Container 1: 14
Container 2: 8
Container 3: 8
Container 4: 4
Container 5: 1
Container 6: 9
Container 7: 1
Container 8: 12
What should be incorrect ( 3x 14 is not fine ):
Container 1: 14
Container 2: 8
Container 3: 4
Container 4: 14
Container 5: 14
Container 6: 9
Container 7: 1
Container 8: 12
You guys have any advice on what the right way is here? I am trying to stay away from a lot of "if's".
Two sets of 15 ranges and shuffle them.
Then slice out 8 items from the array.
$random = array_merge(range(1,15), range(1,15));
shuffle($random);
$random = array_slice($random, 1,8);
Print_r($random);
You could create an array with each selectable element twice.
Then, 8 times, pick a random index from the array and remove it from the array.
$random = [ ];
for ($i = 1; $i <= 15; $i++) {
$random[] = $i;
$random[] = $i; // Twice
}
for ($i = 0; $i < 8; $i++) {
$pick = rand(0, count($random));
// Use $random[$pick]
// Remove array key at index $pick
}
I have the following array
$example=array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
$limit=4 // 4 at the beginning only...
//it used to get incremented automatically to 8,12,16....
At first i want 1,2,3,4as an output for which i have done
foreach($example as $eg)
{
if($eg>$limit)
continue;
}
and i am easily getting 1,2,3,4 at the first then 1,2,3,4,5,6,7,8 then1,2,3,4,5,6,7,8,9,10,11,12
But now i what i want is 1,2,3,4 at the very beginning then 5,6,7,8 then 9,10,11,12 lyk this... how can i get that???
please do help me... :)
AS the
foreach($example as $eg)
{
if($eg>$limit)
continue;
}
is returning only 1,2,3,4 at $limit=4 and 1,2,3,4,5,6,7,8 at $limit=8
i need 1,2,3,4 at $limit=4 and 5,6,7,8 at $limit=8
Have you tried using the helpful built-in functions?
array_chunk($example,$limit);
Alternatively, for more page-like behaviour:
$pagenum = 2; // change based on page
$offset = $pagenum * $limit;
array_slice($example,$offset,$limit);
You would first chunk the array so each chunk has 4 elements, then loop through each chunk:
To change the numbers shown depending on which group, you could do:
$group = $_GET['group'];
$items = array_chunk($example, ceil(count($example)/4)[$group-1];
echo implode(", ", $items);
Then you can go to
yoursite.com/page.php?group=1
And it will output
1, 2, 3, 4
And when you go to
yoursite.com/page.php?group=2
It will output
5, 6, 7, 8
etc.
You can try something like this
$example=array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
$limit = 8;
$limit -= 4;
for($i = $limit; $i < ($limit + 4); $i++)
{
echo $example[$i].' ';
}
Output
//for $limit 4 output 1 2 3 4
//for $limit 8 output 5 6 7 8
//for $limit 16 output 13 14 15 16
Here is a situation:
race 1 = 7
race 2 = 3
race 3 = 1
race 4 = 2
race 5 = 6
race 6 = 2
race 7 = 7
race 8 = 3
The smaller the number the better since these are race positions. race number 1 MUST be added, regardless of it's magnitude and must be added to any 5 others that are selected on merit. So basically I want to use PHP to add up 6 of the best races out of the 8 and the 6 must include 1, regardless of whether it is among the best
I thoughtn of sorting the numbers by having them sorted from lowest to highest and adding the first 6. The problem is that if race 1, is not among the best 6, then this cannot work.
Any help will be appreciated, I am still thinking so I cannot provide anything in terms of what i have tried as everything is still at thought level!
<?php
$race = array( 1 =>7, 2 => 3 );//etc
$sum = $race[1];
unset( $race[1] );
sort( $race, SORT_NUMERIC );
for( $i = 0; $i < 5; $i++ )$sum += array_pop( $race );
<?php
/* if manually creating the array */
$race1 = 7;
$races = array("race2" => 3, "race3" => 1, "race4" => 2); //...
/* if the array is created programmatically (preferred */
$race1 = $races[0];
$races = array_pop($races); //drops first element and resets the index
/* then.... */
asort($races);
$total = $race1;
for($i=0; $i<6; $i++)
{
$total += $races[$i];
}
?>
I'm trying to get the changes between two lists of articles in order to animate the transition between the two lists. Articles can be added, removed or moved (not swapped).
However some articles can't be moved, and in each transition all other articles should be moved below those articles.
For example, if each number represents an article id, and bold represents immovable articles, then:
[1, 2, 3, 4, 5, 6] might become: [2, 4, 1, 6, 7]
I need to work out the changes required, for example in this case:
Move 1 after 4
Remove 5
Add 7 after 6
I have been using a diff algorithm, however it doesn't understand immovable items, so it might suggest:
Move 2 to the beginning
Move 4 after 2
Remove 5
Add 7 after 6
I've tried various things, but can't get it to work reliably.
Moving an immovable item 3 places left is the same thing as moving 3 movable items next to it 1 place right. Use your current diff algorithm, but when it wants to move an immovable item switch to those next to it instead.
UPD. Without multiple moves per article.
Transformations:
1. Remove numbers that are not in the second list (for each item n if not in_list(final_list) then say(n removed)).
[1 2* 4* 5 6] // say("remove 3")
[1 2* 4* 6] // say("remove 5")
2. Make an empty list size of the final list.
[_ _ _ _ _]
3. Prefill it with immovable numbers in their final positions.
[2* 4* _ _ _]
4. Loop through movable items from the first list moving them to their final positions
[2* 4* 1 _ _] // say("move 1 after 4")
[2* 4* 1 6 _] // say("move 6 after 1")
5. Add new items
[2* 4* 1 6 7] // say("add 7 after 6")
It was a fun problem to solve!
Here's the final code, thanks to Alexey:
$immovable = array(2);
$current = array(1,2,8,3,4,5,6);
$new = array(2,7,6,5,4,3,1);
$additions = $additionsCopy = array_diff($new, $current);
foreach($additions as $key => $addition) {
$after = array_key($new, $addition)-1;
$additions[$key] = array(
'value' => $addition,
'after' => ($after < 0 ? 0 : $new[$after])
);
}
for($key = 0; $key < count($new); $key++) {
if(in_array($new[$key], $additionsCopy))
$new = array_remove($new, $key--);
}
$removals = array_diff($current, $new);
for($key = 0; $key < count($current); $key++) {
if(in_array($current[$key], $removals))
$current = array_remove($current, $key--);
}
$lastImmovable = -1;
foreach($new as $key => $item) if(in_array($item, $immovable))
$lastImmovable = $key;
$prev = $lastImmovable < 0 ? 0 : $new[$lastImmovable];
foreach($new as $key => $item) if (!in_array($item, $immovable)) {
$moves[] = array('value' => $item, 'after' =>$prev);
$prev = $item;
}
At this point we can perform $removals, then $moves then $additions