Related
My goal is to get the count of the max amount of numbers, which are increasing in a row in a certain date range. Below is an array. The correct answer of the max amount increasing numbers between 01/13/2021 and 02/17/2021 would be 5 as the numbers 3,8,10,13,15 are growing in that date range.
I managed to search in a certain period of time...
$row = array(
array('01/02/2021', 1),
array('01/13/2021', 4),
array('01/15/2021', 6),
array('01/19/2021', 9),
array('01/30/2021', 5),
array('02/03/2021', 4),
array('02/11/2021', 3),
array('02/12/2021', 8),
array('02/15/2021', 10),
array('02/16/2021', 13),
array('02/17/2021', 15),
array('02/18/2021', 16)
);
$startDateNew = date('m/d/Y', strtotime("2021-01-13"));
$endDateNew = date('m/d/Y', strtotime("2021-02-17"));
foreach($row as $x) {
if(($x[0]>=$startDateNew)&&($x[0]<=$endDateNew) ){
echo 'Found ';
print_r($x);
}
}
I managed also to search the first increasing number sequence in a one-dimensional array as the answer of the code below is 4. But I didn't succeed to continue this search after if-sentence to the next increasing sequence(and the next and the next), so that the correct answer would be 5 in this case.
Including to that, these two searches should combine somehow together.
$numbers = array(1,4,6,9,5,4,3,8,10,13,15);
function LCIS($numbers) {
$counter = 1;
$answer = 1;
for($i = 0; $i < count($numbers) -1; $i++) { //
if ($numbers[$i] < $numbers[$i+1]) { //comparing array indexes together
$counter++; //
$answer = max($answer, $counter); //this doesn't do anything spectacular right now...
continue;
}else {
$counter == 1;
}
return $answer;
}
}
echo LCIS($numbers);
I'm very beginner at php coding. Could you help me, please?
Well if you have already 2 parts of the code you just need to combine them together. What I suggest is to feed the $numbers array during checking if the $row array element is in certain date range.
function LCIS($numbers)
{
$counter = 1;
$answer = 1;
for ($i = 0; $i < count($numbers) - 1; $i++) { //
if ($numbers[$i] < $numbers[$i + 1]) { //comparing array indexes together
$counter++; //
$answer = max($answer, $counter); //this doesn't do anything spectacular right now...
} else {
$counter = 1;
}
}
return $answer;
}
$row = array(
array('01/02/2021', 1),
array('01/13/2021', 4),
array('01/15/2021', 6),
array('01/19/2021', 9),
array('01/30/2021', 5),
array('02/03/2021', 4),
array('02/11/2021', 3),
array('02/12/2021', 8),
array('02/15/2021', 10),
array('02/16/2021', 13),
array('02/17/2021', 15),
array('02/18/2021', 16)
);
$numbers = array();
$startDateNew = date('m/d/Y', strtotime("2021-01-13"));
$endDateNew = date('m/d/Y', strtotime("2021-02-17"));
foreach($row as $x) {
if(($x[0]>=$startDateNew)&&($x[0]<=$endDateNew) ){
$numbers[] = $x[1];
}
}
echo LCIS($numbers);
BTW: I have modified a little your LCIS function and it will run faster and more correct.
QUESTION:
Given an array of integers, find the pair of adjacent elements that has the largest product and return that product.
Example:
https://app.codesignal.com/arcade/intro/level-2
For inputArray = [3, 6, -2, -5, 7, 3], the output should be
adjacentElementsProduct(inputArray) = 21.
7 and 3 produce the largest product.
Input/Output
Input:
inputArray: [3, 6, -2, -5, 7, 3]
Expected Output:
21
SOLUTION: My code that doesn't work:
function adjacentElementsProduct($inputArray) {
$total = 0;
$temp = 0;
$maxProduct = 0;
$var = 0;
if ($inputArray.count == 1) return 0;
for ($i = 0; $i < $inputArray[$inputArray.count-1]; $i++) {
if ($inputArray[i] + $inputArray[i+1] > $maxProduct) {
$maxProduct = $inputArray[i] * $inputArray[i+1];
}
}
return $maxProduct;
}
As with any programming task, the trick is to tackle it piece by piece. You tend to find your code is more readable when you break problems down into small components.
You need to:
Find the product of adjacent elements in an array
Find the largest product in that group of values
You can approach this without a large number of variables, nesting, etc.
function adjacentElementsProduct(array $inputs) {
$products = [];
for ($i = 1; $i < count($inputs); $i++) {
$products[] = $inputs[$i - 1] * $inputs[$i];
}
return max($products);
}
All we're doing is looping through the input array, starting with the second element. Calculating the product of the previous element and the current element then putting the result into an array of products. Finally we run that through max() which is going to handle finding the largest value for us.
Important to note: there's no validation taking place here. Can you trust that your array will only ever contain numerical values? Will it always contain at least two elements? If not you'll want to account for that.
Here is how I would do it
$inputArray = [3, 6, -2, -5, 7, 3];
function adjacentElementsProduct($inputArray) {
$max = 0;
for($i = 0; $i < (sizeof($inputArray) - 1); $i++){
$b = $i+1;
if($inputArray[$i] > 0 && $inputArray[$b] > 0){
$max = (($inputArray[$i] * $inputArray[$b]) > $max) ? ($inputArray[$i] * $inputArray[$b]) : $max;
}
}
return $max;
}
echo adjacentElementsProduct($inputArray); // Outputs 21
function adjacentElementsProduct($inputArray) {
$res = [];
for($j=0;$j<count($inputArray);$j++){
$res[] = $inputArray[$j]*$inputArray[$j+1];
}
return (max($res) < 0) ? 0 : max($res);
}
As with any programming task, the trick is to tackle it piece by piece. You tend to find your code is more readable when you break problems down into small components.
You need to:
Find the product of adjacent elements in an array
Find the largest product in that group of values
In PHP its as below:
function adjacentElementsProduct($inputArray) {
$res = [];
for($j=1;$j<count($inputArray);$j++){
$res[] = $inputArray[$j-1]*$inputArray[$j];
}
return max($res);
}
$a = [3, 6, -2, -5, 7, 3]
echo adjacentElementsProduct($a); //21
Suppose I have an array similar to this:
$months = Array('3','6','12','15','18','21','24');
and I have $n = 5, what would be a good way to find that $n falls in array ?
also element should be append after 3 & before 6 because 5 in between 3 & 6
e.g.
$n = 5; then array will be
$months = Array('3','5','6','12','15','18','21','24');
$n = 7; then array will be
$months = Array('3','6','7','12','15','18','21','24');
also i need to display progress according to $n
e.g.
$n=3 then up to $3 color will get filled
$n=5 then color will get filled up to middle of 3 & 5
i have placed array value on div & i need to display progress accordingly.
PROGRESS BAR EXAMPLE
http://awesomescreenshot.com/04937zko93
Assuming the months array is initially sorted, we iterate through that array and find the exact position to insert $n, partition that array in two and insert $n in middle of the slices
for($pos = 0; $pos < count($months); $pos++) {
if($months[$pos] > $n) {
break;
}
}
$end_part = array_slice($months, $pos);
$first_part = array_slice($months, 0, $pos);
$first_part[] = $n;
$months = array_merge($first_part, $end_part);
$n = 7;
$months = Array('3','6','12','15','18','21','24');
$i = 0;
foreach ($months as $k => $v) {
if ($n < $v) {
$months = array_merge(array_slice($months, 0, $i), array("$n"), array_slice($months, $i, count($months)));
break;
}
++$i;
}
var_dump($months);
This is how to insert the value at the correct position in your array:
$months = [3, 6, 12, 15, 18, 21, 24];
$n = 5;
$idx = count(array_filter($months, function($val) use($n) {
return $val < $n;
}));
array_splice($months, $idx, 0, [$n]);
This is how to calculate the progress to use for your progress bar, assuming that:
The first value (3 in this example) is 0%
That the last value (24) is 100%, and
There is the same difference between each number in the array (3 in this case)
-
$pct = ($n - min($months)) / (max($months) - min($months)) * 100;
I'm trying to build an algorithm for processing bracket sheet of competitions. I need to go through a range of numbers. For each number there will be the athlete name. Numbers are assigned to athletes randomly but the number's pairing must always stay the same. There are two groups odd and even, i.e. A and B.
The only problem that I can't find the proper algorithm to iterate numbers the exact way as follows:
Group A:
--------
1
17
9
25
------
5
21
13
29
------
3
19
11
27
------
7
23
15
31
Group B:
--------
2
18
10
26
------
6
22
14
30
------
4
20
12
28
------
8
24
16
32
Could someone please help with advice or example of how to get the output above?
EDIT 1:
The example above is the bracket sheet for 32 athletes! Same logic must be applied if you use a sheet for 4,8,16,64 or 128 athletes!
EDIT 2:
Let's make it more clear with examples of the sheet for 4 athletes and then the sheet for 16 athletes.
The sheet for 4 athletes:
Group A:
--------
1
3
Group B:
--------
2
4
The sheet for 16 athletes:
Group A:
--------
1
9
5
13
------
3
11
7
15
Group B:
--------
2
10
6
14
------
4
12
8
16
EDIT 3:
The last part, is that I'm planning to have an array with athlete name and its status in it.
By status I mean that, if the athlete has been a champion previously (strong), then he/she gets 1 for status, if the athlete's previous achievements are not known or minimal (weak), then the status is 0. It's done that way, so we could separate strongest athletes into different groups and make sure that they will not fight against each other in the first fight but rather meet each other closer to the semi-final or final.
Example of PHP array:
$participants = array(
array("John", 0),
array("Gagan", 0),
array("Mike Tyson", 1),
array("Gair", 0),
array("Gale", 0),
array("Roy Johnes", 1),
array("Galip", 0),
array("Gallagher", 0),
array("Garett", 0),
array("Nikolai Valuev", 1),
array("Garner", 0),
array("Gary", 0),
array("Gelar", 0),
array("Gershom", 0),
array("Gilby", 0),
array("Gilford", 0)
);
From this example we see that those, who have status 1 must be in different groups, i.e. A and B. But we have only two groups of numbers odd and even and in this example, there are 3 strong athletes. Thus two of them will be at the same group. The final result must be, that those two strong athletes, that got in the same group, must not meet at the very first fight (it means that they will not be on the same pair of numbers and as far away from each other as possible, so they wouldn't meet on the second fight as well).
Then randomly, I'm planning to rearrange the array and send athletes to the bracket sheet - every time, with different numbers, every time, those that have a flag 1 go to different groups and/or never meet at the first fight and every time, athletes' names assigned to the same pair of numbers.
Considering the number of participants is always a power of 2, this piece of code should give you the order you're expecting.
function getOrder($numberOfParticipants) {
$order = array(1, 2);
for($i = 2; $i < $numberOfParticipants; $i <<= 1) {
$nextOrder = array();
foreach($order as $number) {
$nextOrder[] = $number;
$nextOrder[] = $number + $i;
}
$order = $nextOrder;
}
return $order; // which is for instance [1, 17, 9, 25, and so on...] with 32 as argument
}
About the way it works, let's take a look at what happens when doubling the number of participants.
Participants | Order
2 | 1 2
4 | 1 3=1+2 2 4=2+2
8 | 1 5=1+4 3 7=3+4 2 6=2+4 4 8=4+4
... |
N | 1 X Y Z ...
2N | 1 1+N X X+N Y Y+N Z Z+N ...
The algorithm I used is the exact same logic. I start with an array containing only [1, 2] and $i is actually the size of this array. Then I'm computing the next line until I reach the one with the right number of participants.
On a side note: $i <<= 1 does the same than $i *= 2. You can read documentation about bitwise operators for further explanations.
About strong athletes, as you want to keep as much randomness as possible, here is a solution (probably not optimal but that's what I first thought):
Make two arrays, one with strongs and one with weaks
If there are no strongs or a single one, just shuffle the whole array and go to 8.
If there are more strongs than weaks (dunno if it can happen in your case but better be safe than sorry), shuffle the strongs and put the last ones with weaks so both arrays are the same size
Otherwise, fill up the strongs with null elements so the array size is a power of 2 then shuffle it
Shuffle the weaks
Prepare as many groups as they are elements in the strongs array and put in each group one of the strongs (or none if you have a null element) and complete with as many weaks as needed
Shuffle each group
Return the participants, ordered the same way than previous function resulting array
And the corresponding code:
function splitStrongsAndWeaks($participants) {
$strongs = array();
$weaks = array();
foreach($participants as $participant) {
if($participant != null && $participant[1] == 1)
$strongs[] = $participant;
else
$weaks[] = $participant;
}
return array($strongs, $weaks);
}
function insertNullValues($elements, $totalNeeded)
{
$strongsNumber = count($elements);
if($strongsNumber == $totalNeeded)
return $elements;
if($strongsNumber == 1)
{
if(mt_rand(0, 1))
array_unshift($elements, null);
else
$elements[] = null;
return $elements;
}
if($strongsNumber & 1)
$half = ($strongsNumber >> 1) + mt_rand(0, 1);
else
$half = $strongsNumber >> 1;
return array_merge(insertNullValues(array_splice($elements, 0, $half), $totalNeeded >> 1), insertNullValues($elements, $totalNeeded >> 1));
}
function shuffleParticipants($participants, $totalNeeded) {
list($strongs, $weaks) = splitStrongsAndWeaks($participants);
// If there are only weaks or a single strong, just shuffle them
if(count($strongs) < 2) {
shuffle($participants);
$participants = insertNullValues($participants, $totalNeeded);
}
else {
shuffle($strongs);
// If there are more strongs, we need to put some with the weaks
if(count($strongs) > $totalNeeded / 2) {
list($strongs, $strongsToWeaks) = array_chunk($strongs, $totalNeeded / 2);
$weaks = array_merge($weaks, $strongToWeaks);
$neededGroups = $totalNeeded / 2;
}
// Else we need to make sure the number of groups will be a power of 2
else {
$neededGroups = 1 << ceil(log(count($strongs), 2));
if(count($strongs) < $neededGroups)
$strongs = insertNullValues($strongs, $neededGroups);
}
shuffle($weaks);
// Computing needed non null values in each group
$neededByGroup = $totalNeeded / $neededGroups;
$neededNonNull = insertNullValues(array_fill(0, count($participants), 1), $totalNeeded);
$neededNonNull = array_chunk($neededNonNull, $neededByGroup);
$neededNonNull = array_map('array_sum', $neededNonNull);
// Creating groups, putting 0 or 1 strong in each
$participants = array();
foreach($strongs as $strong) {
$group = array();
if($strong != null)
$group[] = $strong;
$nonNull = array_shift($neededNonNull);
while(count($group) < $nonNull)
$group[] = array_shift($weaks);
while(count($group) < $neededByGroup)
$group[] = null;
// Shuffling again each group so you can get for instance 1 -> weak, 17 -> strong
shuffle($group);
$participants[] = $group;
}
// Flattening to get a 1-dimension array
$participants = call_user_func_array('array_merge', $participants);
}
// Returned array contains participants ordered the same way as getOrder()
// (eg. with 32 participants, first will have number 1, second number 17 and so on...)
return $participants;
}
If you want the resulting array to have as indexes the number in the bracket, you can simply do:
$order = getOrder(count($participants));
$participants = array_combine($order, shuffleParticipants($participants, count($order)));
Okay, I finally managed to convert my Tcl code to PHP! I changed some things too:
<?php
// Function generating order participants will be placed in array
function getBracket($L) {
// List will hold insert sequence
$list = array();
// Bracket will hold final order of participants
$bracket = array();
// The algorithm to generate the insert sequence
for ($n = 1; $n <= $L; $n += 1) {
// If 'perfect' number, just put it (Perfect no.s: 2, 4, 8, 16, 32, etc)
if (substr(log($n)/log(2), -2) == ".0") {
$list[] = $n;
// If odd number, stuff...
} elseif ($n % 2 == 1) {
$list[] = $list[($n-1)/2];
// Else even number, stuff...
} else {
$list[] = $list[$n/2-1]+$n/2;
}
}
// Insert participant order as per insert sequence
for ($i = 1; $i <= sizeof($list); $i += 1) {
$id = $i-1;
array_splice($bracket, $list[$id], 0, $i);
}
return $bracket;
}
// Find number of participants over 'perfect' number if any
function cleanList($L) {
for ($d = 1; $L > $d; $d += 1) {
$sq = $L-pow(2,$d);
if($sq == 0) {break;}
if($sq < 0) {
$d = pow(2,$d-1);
$diff = $L-$d;
break;
}
}
return $diff;
}
$participants = array(
array(0, "John", 2),
array(1, "Gagan", 1),
array(2, "Mike Tyson", 1),
array(3, "Gair", 1),
array(4, "Gale", 0),
array(5, "Roy Johnes", 0),
array(6, "Galip", 0),
array(7, "Gallagher", 0),
array(8, "Garett", 0),
array(9, "Nikolai Valuev", 0),
array(10, "Garner", 1),
array(11, "Gary", 0),
array(12, "Gelar", 0),
array(13, "Gershom", 1),
array(14, "Gilby", 0),
array(15, "Gilford", 1),
array(16, "Arianna", 0)
);
// Extract strength of participant
foreach ($participants as $array) {
$finorder[] = $array[2];
}
// Sort by strength, strongest first
array_multisort($finorder,SORT_DESC,$participants);
$order = array();
$outside = array();
// Remove participants above 'perfect' number
$remove = cleanList(sizeof($participants));
for ($r = 1; $r <= $remove; $r += 1) {
$removed = array_shift($participants);
$outside[] = $removed;
}
// Get corresponding bracket
$res = getBracket(sizeof($participants));
foreach ($res as $n) {
$order[] = $n;
}
// Align bracket results with participant list
array_multisort($order, $participants);
$participants = array_combine($res, $participants);
echo "The final arrangement of participants\n";
print_r($participants);
print_r($outside);
?>
Codepad demo
To get the logic for the order of insertion of elements, I used this pattern.
Also, since I'm not too familiar with PHP, there might be ways to make some things shorter, but oh well, as long as it works ^^
EDIT: Fixed an issue with first participant sorting and added new ticket numbers. For results without old ticket numbers, see here.
EDIT2: Managed to move keys into arrays; see here.
EDIT3: I thought that 'extra' participants should go outside the bracket. If you want null instead in the bracket, you can use this.
EDIT4: Somehow, PHP versions on codepad broke some stuff... fixing it below and removing initial index...:
<?php
// Function generating order participants will be placed in array
function getBracket($L) {
// List will hold insert sequence
$list = array();
// Bracket will hold final order of participants
$bracket = array();
// The algorithm to generate the insert sequence
for ($n = 1; $n <= $L; $n += 1) {
// If 'perfect' number, just put it (Perfect no.s: 2, 4, 8, 16, 32, etc)
if (int(log($n)/log(2)) || $n == 1) {
$list[] = $n;
// If odd number, stuff...
} elseif ($n % 2 == 1) {
$list[] = $list[($n-1)/2];
// Else even number, stuff...
} else {
$list[] = $list[$n/2-1]+$n/2;
}
}
// Insert participant order as per insert sequence
for ($i = 1; $i <= sizeof($list); $i += 1) {
$id = $list[$i-1]-1;
array_splice($bracket, $id, 0, $i);
}
return $bracket;
}
// Find number of participants over 'perfect' number if any
function cleanList($L) {
for ($d = 1; $L > $d; $d += 1) {
$diff = $L-pow(2,$d);
if($diff == 0) {break;}
if($diff < 0) {
$diff = pow(2,$d)-$L;
break;
}
}
return $diff;
}
$participants = array(
array("John", 2),
array("Gagan", 1),
array("Mike Tyson", 1),
array("Gair", 1),
array("Gale", 0),
array("Roy Johnes", 0),
array("Galip", 0),
array("Gallagher", 0),
array("Garett", 0),
array("Nikolai Valuev", 0),
array("Garner", 1),
);
// Extract strength of participant
foreach ($participants as $array) {
$finorder[] = $array[2];
}
// Sort by strength, strongest first
array_multisort($finorder,SORT_DESC,$participants);
$order = array();
// Add participants until 'perfect' number
$add = cleanList(sizeof($participants));
for ($r = 1; $r <= $add; $r += 1) {
$participants[] = null;
}
// Get corresponding bracket
$res = getBracket(sizeof($participants));
// Align bracket results with participant list
foreach ($res as $n) {
$order[] = $n;
}
array_multisort($order, $participants);
$participants = array_combine($res, $participants);
echo "The final arrangement of participants\n";
print_r($participants);
?>
ideone
viper-7
This sketchy code might be what you want:
<?php
class Pair
{
public $a;
public $b;
function __construct($a, $b) {
if(($a & 1) != ($b & 1))
throw new Exception('Invalid Pair');
$this->a = $a;
$this->b = $b;
}
}
class Competition
{
public $odd_group = array();
public $even_group = array();
function __construct($order) {
$n = 1 << $order;
$odd = array();
$even = array();
for($i = 0; $i < $n; $i += 4) {
$odd[] = $i + 1;
$odd[] = $i + 3;
$even[] = $i + 2;
$even[] = $i + 4;
}
shuffle($odd);
shuffle($even);
for($i = 0; $i < count($odd); $i += 2) {
$this->odd_group[] = new Pair($odd[$i], $odd[$i+1]);
$this->even_group[] = new Pair($even[$i], $even[$i+1]);
}
echo "Odd\n";
for($i = 0; $i < count($this->odd_group); ++$i) {
$pair = $this->odd_group[$i];
echo "{$pair->a} vs. {$pair->b}\n";
}
echo "Even\n";
for($i = 0; $i < count($this->even_group); ++$i) {
$pair = $this->even_group[$i];
echo "{$pair->a} vs. {$pair->b}\n";
}
}
}
new Competition(5);
?>
I am having trouble trying to figure out how to get data ordered like below. The total numbers don't matter; it would follow the same pattern from any number in the logical order of 0, 1, 2, 3, 4, 5, 6, etc. So essentially, starting at 0, 2, 3, 4, etc. where 1 would be placed after the maximum number, and where 0 can be a variable I set statically. I am having issues with progressing all the way to max number and then continuing, e.g.
..., 97, 98, 99, 100, 1, 2, ...
and then progressing with the order,
..., 98, 99, 100, 1, 2, 3, ...
and so on until 1, 2, 3, 4, 5, 6, ...
and store this all into the multidimensional array below.
$set = array(
array('0','0','0','0','0','0','0','0','0','0','0'),
array('0','2','3','4','5','6','7','8','9','10','1'),
array('0','3','4','5','6','7','8','9','10','1','2'),
array('0','4','5','6','7','8','9','10','1','2','3'),
array('0','5','6','7','8','9','10','1','2','3','4'),
array('0','6','7','8','9','10','1','2','3','4','5'),
array('0','7','8','9','10','1','2','3','4','5','6'),
array('0','8','9','10','1','2','3','4','5','6','7'),
array('0','9','10','1','2','3','4','5','6','7','8'),
array('0','10','1','2','3','4','5','6','7','8','9'),
array('0','1','2','3','4','5','6','7','8','9','10'),
);
I did the above because I couldn't figure out a looping pattern; if I could figure that out I wouldn't need to enter in the data manually and could create a form by which any number could be chosen, following this pattern.
Notice that other than the first row and column, each row is just the previous shifted left, with the next value added on:
$max = 10;
// First row (full of 0)
$set = array(array_fill(0, $max + 1, 0));
$row = array();
for($i = 1; $i <= $max; $i++)
$row[] = $i;
$row[] = 1; // $row = [2,3,4,...,$max,1]
for($i = 0; $i < $max; $i++){
$set[] = array_merge(array(0), $row);
$row = array_map(function($x) use ($max){ // Requires PHP 5.3
$result = ($x + 1) % $max;
return 0 === $result ? $max : $result;
}, $row);
}
Codepad
It's of course fairly trivial to make this store strings instead of integers if you require that.
$array = array();
$max = 10;
for ($i = 0; $i < $max; $i++)
{
$num = $i + 2;
$array[$i][] = 0;
for ($j = 0; $j < $max; $j++)
{
if ($num == $max + 1)
$num = 1;
$array[$i][] = $num;
$num++;
}
}
var_dump($array);