I have a time string from 0 to 24. like this
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
Now if it is 2 oclock, I want to select every 4th hour. so from above it will be
2, 6, 10, 14, 18, 22
I am trying to wrap my head around it to get this going
thanks
I have tried this
if(range($hour, 23, 4)){
print_r($hour);echo '<br />';
}
but it still prints all the hours in that array
EDIT
here is the code
$hourlyData->hour is just an hour digit, like 0 or 1 or 2 etc upto 23
foreach($jason->hours as $hourlyData){
if(range($hourlyData->hour, 23, 3)){
// print here to check if the correct time is used
print_r($hourlyData->hour);echo '<br />';
}
}
Why use a "time string" for this? It's built-in. For an array:
$hours = range(2, 23, 4); // get every 4th hour starting from 2
And for a string:
$str = implode(', ', range(2, 23, 4));
Finally, to unlock the magic number elimination achievement:
define('HOURS_IN_DAY', 24);
$str = implode(', ', range(2, HOURS_IN_DAY - 1, 4));
Related
I need to find the number of coins that make a given value where coins are in decimals and there is a possibility that the algorithm will return more coins (money) because there is no way to return the exact value where the returned amount is close to the given value.
For example:
Coins: [23, 29.90, 34.50]
Value: 100
Possible solutions:
Solution 1: 34.60, 34.50, 29.90, 23 (122)
Solution 2: 29.90, 29.90, 29.90 ,29.90 (119.90)
Solution 3: 23, 23, 23, 23, 23 (115)
Solution 4: 23, 23, 23, 34.50 (103.5)
Based on the possible solutions, the clear winner is "Solution 4" and I am looking for an algorithm that will help me to solve this issue. I don't care how many coins are used I just need to be sure that returned values in coins are as close as passed/desired value.
Does someone know the solution or algorithm for this case?
Best Regards.
Greedy algorithm assumes that you get the largest possible coin, then the next possible and so on until you reach the sum. But it does not provide the best solution in general case.
So consider using of table containing possible sums:
Multiply sum and all nominals by 100 to work in integers.
Make array A[] of length 1 + sum + largest_coin, filled with zeros, set A[0] into -1.
For every coin nominal C walk through array. If A[i-C] is not zero, put value C into A[i]
After all scan array range A[sum]..A[max] to find the first non-zero item. It's index K represents the best sum. This cell contains the last coin added - so you can unwind the whole combination, walking down until index 0: A[k] => A[k - A[k]] an so on
Python code
def makesum(lst, summ):
mx = max(lst)
A = [-1] + [0]*(mx+summ)
for c in lst:
for i in range(c, summ + c + 1):
if A[i - c]:
A[i] = c
print(A)
#look for the smallest possible combination >= summ
for k in range(summ, summ + mx + 1):
if A[k]:
break
if (k == summ + mx + 1):
return
# unwind combination of used coins
while (k > 0):
print(A[k])
k = k - A[k]
makesum([7, 13, 21], 30)
Array for reference. Non-zero entries - for possible sums.
[-1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 13, 7, 0, 0, 0, 0, 0, 13, 21, 0, 0,
0, 0, 13, 13, 21, 0, 0, 0, 0, 13, 21, 21, 0, 0, 0, 13, 13, 21, 21, 0, 0, 0,
0, 21, 21, 21, 0, 0]
Combination:
13
13
7
Getting started
I do not have enough reputation to ask in comments I wanted to ask you further questions but here it goes.I believe this can get you started
-Assuming we are not sure how many coins a user is going to pick
-Any of the coins can be the same amount as the others but have to be treated as different inputs
-Any number of coins can be added together so that the sum closest to the desired max can be accepted
What exactly is the script intended to achieve
A user picks random number of coins which are recorded then put into array.Any random number of coins can be picked and added and if the sum gets closer to a specific threshold those coins are accepted
Concept
<?php
$arrX = array("1.1","20.1","3.5","4","5.7","6.8","7.3","8.6","9","10"); //random coins from user
$minthresh = "30";
$desired = "33";
$maxthresh = "35"; //A threshold is necessary if the desired amount is not enforced
$randIndex = array_rand($arrX, 2); //Pick any random two coins avoid the same coin twice
$sumofpair = $arrX[$randIndex[0]] + $arrX[$randIndex[1]]." Possible acceptable sum<br>"; //Debug to see which two
coins are picked and how much they give
print_r($randIndex[0]);
echo " pair with ";
print_r($randIndex[1]);
echo " = ".$sumofpair; //Debug to see which two coins are picked and how much they give
if (($sumofpair >= "30") && ($sumofpair <= "35")){ //Check if the sum is within the threshold
echo "<br>found something<br>";
echo "<br>This ".$arrX[$randIndex[0]]."+".$arrX[$randIndex[1]]." Gets you this ".$sumofpair." Which is very close to
".$desired;
//if a pair is found show which pair exactly and how much did the pair make
} else { echo "<br>No match so far.Refresh again</br>"; //If the pair do not match refresh until a pair is found...See
below for more info on this }
?>
If you were to solve the need for refresh.You will run this in a loop until the pair that gives you the desired is found
You can expand this to check for 3 random and 4 random and so on.
randIndex = array_rand($arrX, 3)...randIndex = array_rand($arrX, 4)....
Php.net does not say array_rand function cannot pick the same keys.Personally never seen two picked at the same time.If that does happen.
The code should be expanded to record coins that are already picked,which should also prevent adding a coin against itself.
Here is a clean code...run this any sum that return amount between 29 and 35 should return found.
<?php
$arrX = array("1.1","20.1","3.5","4","5.7","6.8","7.3","8.6","9","10");
$desired = "32";
$randIndex = array_rand($arrX, 2);
$sumofpair = $arrX[$randIndex[0]] + $arrX[$randIndex[1]];
echo $arrX[$randIndex[0]];
echo " pair with ";
echo $arrX[$randIndex[1]];
echo " = ".$sumofpair;
if (($sumofpair >= "30") && ($sumofpair <= "35")){
echo "<br>This coin ".$arrX[$randIndex[0]]."+ This coin ".$arrX[$randIndex[1]]." = ".$sumofpair." This amount ~ equal
to ".$desired;
} else { echo "<br>Not a match so far.Refresh again</br>"; }
?>
I truly thinking too long to find the logic/ algorithm to do this thing. Then I just use if else but I know this is bad because there will be too much statement.
I have number format group below to split the input number :
01 (Get 14 digits after this number format)
3101 (Get 6 digits after this number format)
3102 (Get 6 digits)
3202 (Get 6 digits)
13 (Get 6 digits)
15 (Get 6 digits)
11 (Get 6 digits)
21 (Get the rest)
Some of rules :
01 always in first sequence
21 always in last sequence
other number format except 01 and 21 can be in any sequence position.
The same prefix number format cannot be repeat
example, Input Number : 010069008517306731020020001319100421191004091395
The Result Should be :
01 : 00690085173067
3102 : 002000
13 : 191004
21 : 191004091395
Currently I only use IF ELSE statement to get the digits after.
This is my pieces of code using PHP. This code can only handle that example input above. There will be possibility of other sequence number format as per rules, but it will difficult if only use if else statement like this.
$first = substr($input, 0, 2);
if ($first == 01) {
$itemCode = substr($input, 2, 14); // get the 6 digits after 01
$second = substr($input, 16, 4);
if ($second == 3102) {
$quantity = substr($input, 20, 6); // get the 6 digits after 3102
$third = substr($input, 26, 2);
if ($third == 13) {
$packedDate = substr($input, 28, 6); // get the 6 digits after 13
$fourth = substr($input, 34, 2);
if ($fourth == 21) {
$serialNumber = substr($scanner, 36); // get the rest number after 21
}
}
}
}
Is there any good way to solve this thing?
If the prefixes won't repeat, you can use preg_match_all to match the prefixes with each of their trailing digits, using array_combine to create arrays of digits indexed by their prefixes:
$input = '010069008517306731020020001319100421191004091395';
if (preg_match_all('/(01)(\d{14})|(310[12]|3202|1[135])(\d{6})|(21)(\d+)/', $input, $matches)) {
$numbers = array_filter(array_combine($matches[1], $matches[2]) +
array_combine($matches[3], $matches[4]) +
array_combine($matches[5], $matches[6]));
print_r($numbers);
}
else {
echo "Invalid input!";
}
Output:
Array
(
[01] => 00690085173067
[3102] => 002000
[13] => 191004
[21] => 191004091395
)
Demo on 3v4l.org
Ok, so the question is kind of awkwardly phrased, but I hope this will clear things up.
I have this sample 2d array.
$array = array(
array(1, 0, 0, 0, 1, 0, 0, 1),
array(0, 0, 1, 1, 1, 1, 0, 1),
array(0, 1, 1, 0, 1, 0, 0, 0),
array(0, 1, 1, 0, 0, 0, 1, 0),
array(1, 0, 0, 0, 1, 1, 1, 1),
array(0, 1, 1, 0, 1, 0, 1, 0),
array(0, 0, 0, 0, 0, 0, 0, 1)
);
When iterated by rows (and terminating each row with \n), and for every row then iterated by column, it will echo something like this: (░░ = 0, ▓▓ = 1)
▓▓░░░░░░▓▓░░░░▓▓
░░░░▓▓▓▓▓▓▓▓░░▓▓
░░▓▓▓▓░░▓▓░░░░░░
░░▓▓▓▓░░░░░░▓▓░░
▓▓░░░░░░▓▓▓▓▓▓▓▓
░░▓▓▓▓░░▓▓░░▓▓░░
░░░░░░░░░░░░░░▓▓
But what I'd like to do is to "analyse" the array and only leave 1 contiguous shape (the one with the most "cells"), in this example, the result would be:
░░░░░░░░▓▓░░░░░░
░░░░▓▓▓▓▓▓▓▓░░░░
░░▓▓▓▓░░▓▓░░░░░░
░░▓▓▓▓░░░░░░░░░░
▓▓░░░░░░░░░░░░░░
░░▓▓▓▓░░░░░░░░░░
░░░░░░░░░░░░░░░░
My initial approach was to:
Assign each ▓▓ cell a unique number (be it completely random, or the current iteration number):
01 02 03
04050607 08
0910 11
1213 14
15 16171819
2021 22 23
24
Iterate through the array many, MANY times: every iteration, each ▓▓ cell assumes the largest unique number among his neighbours. The loop would go on indefinitely until there's no change detected between the current state and the previous state. After the last iteration, the result would be this:
01 21 08
21212121 08
2121 21
2121 24
21 24242424
2121 24 24
24
Now it all comes down to counting the value that occurs the most. Then, iterating once again, to turn all the cells whose value is not the most popular one, to 0, giving me the desired result.
However, I feel it's quite a roundabout and computationally heavy approach for such a simple task and there has to be a better way. Any ideas would be greatly appreciated, cheers!
BONUS POINTS: Divide all the blobs into an array of 2D arrays, ordered by number of cells, so we can do something with the smallest blob, too
Always fun, these problems. And done before, so I'll dump my code here, maybe you can use some of it. This basically follows every shape by looking at a cell and its surrounding 8 cells, and if they connect go to the connecting cell, look again and so on...
<?php
$shape_nr=1;
$ln_max=count($array);
$cl_max=count($array[0]);
$done=[];
//LOOP ALL CELLS, GIVE 1's unique number
for($ln=0;$ln<$ln_max;++$ln){
for($cl=0;$cl<$cl_max;++$cl){
if($array[$ln][$cl]===0)continue;
$array[$ln][$cl] = ++$shape_nr;
}}
//DETECT SHAPES
for($ln=0;$ln<$ln_max;++$ln){
for($cl=0;$cl<$cl_max;++$cl){
if($array[$ln][$cl]===0)continue;
$shape_nr=$array[$ln][$cl];
if(in_array($shape_nr,$done))continue;
look_around($ln,$cl,$ln_max,$cl_max,$shape_nr,$array);
//SET SHAPE_NR to DONE, no need to look at that number again
$done[]=$shape_nr;
}}
//LOOP THE ARRAY and COUNT SHAPENUMBERS
$res=array();
for($ln=0;$ln<$ln_max;++$ln){
for($cl=0;$cl<$cl_max;++$cl){
if($array[$ln][$cl]===0)continue;
if(!isset($res[$array[$ln][$cl]]))$res[$array[$ln][$cl]]=1;
else $res[$array[$ln][$cl]]++;
}}
//get largest shape
$max = max($res);
$shape_value_max = array_search ($max, $res);
//get smallest shape
$min = min($res);
$shape_value_min = array_search ($min, $res);
// recursive function: detect connecting cells
function look_around($ln,$cl,$ln_max,$cl_max,$nr,&$array){
//create mini array
$mini=mini($ln,$cl,$ln_max,$cl_max);
if($mini===false)return false;
//loop surrounding cells
foreach($mini as $v){
if($array[$v[0]][$v[1]]===0){continue;}
if($array[$v[0]][$v[1]]!==$nr){
// set shape_nr of connecting cell
$array[$v[0]][$v[1]]=$nr;
// follow the shape
look_around($v[0],$v[1],$ln_max,$cl_max,$nr,$array);
}
}
return $nr;
}
// CREATE ARRAY WITH THE 9 SURROUNDING CELLS
function mini($ln,$cl,$ln_max,$cl_max){
$look=[];
$mini=[[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]];
foreach($mini as $v){
if( $ln + $v[0] >= 0 &&
$ln + $v[0] < $ln_max &&
$cl + $v[1] >= 0 &&
$cl + $v[1] < $cl_max
){
$look[]=[$ln + $v[0], $cl + $v[1]];
}
}
if(count($look)===0){return false;}
return $look;
}
Here's a fiddle
I can only think of a few minor improvements:
Keep a linked list of the not empty fields. In step 2 you do not need to touch n² matrix-elements, you only need to touch the ones in your linked list. Which might be much less depending how sparse your matrix is.
You only need to compare to the right, right-down, left-down and down directions. Otherwise The other directions are already checked from the former row/column. What I mean: When I am greater that my right neighbour, I can already change the number of the right neighbour. (same for down and right-down). This halfs the number of compairs.
If your array size isn't huge and memory won't be a problem maybe a recursive solution would be faster. I found a c++ algorithm that does this here:
https://www.geeksforgeeks.org/find-length-largest-region-boolean-matrix/
$MarketValue = number_format(100000 * 4, 2, '.',',');
$purchasing_val =number_format(100000 * 6, 2, '.',',');
$pls = $purchasing_val - $MarketValue ;
The Above Code result should be 200000 but its just showing 200, its only occur when i format the values, Where's the error ? Thanks in advance.
You are not supposed to format then calculate.
Try to calculate, then format the number.
$MarketValue = 100000 * 4;
$purchasing_val = 100000 * 6;
$pls = number_format($purchasing_val - $MarketValue, 2, '.', ',');
EDIT:
As you asked, in case you want to show them as formatted, you have many options.
You could just echo them as number_format($purchasing_val, 2, '.', ','); and number_format($MarketValue, 2, '.', ',');
or you could store them as another variable to show later on like
$FormattedMarketValue = number_format($MarketValue, 2, '.', ',');
$Formattedpurchasing_val = number_format($purchasing_val, 2, '.', ',');
And when ever in your script you echo the two variables $FormattedMarketValue and $Formattedpurchasing_val
I'd like to format given string with following rules;
Get only digits out of it
Get them in 4 digit groups
Each group must lead with 0's
There must be 3 groups.
Given : 1234 Expected Result: 0000-0000-1234
Given : 123 Expected Result: 0000-0000-0123
Given : 12345 Expected Result: 0000-0001-2345
Given : 123456789012345 Expected Result: 1234-5678-9012
Is there anyway to achieve this without getting into creating a method / function for it? Such as with regex and / or using sprintf?
Use str_pad() to format the strings with all zeros, and chunk_split() to add a - for every 4 characters, substr() is responsable for limit the lenght of string at 14 characters, in the last example the string have 16 characters, substr() fix this.
$arr = ['1234', '123', '12345', '123456789012345'];
foreach($arr as $item){
$str = str_pad($item, 12, '0',STR_PAD_LEFT);
echo substr(chunk_split($str, 4, '-'), 0, 14) .'<br>';
}
Output:
0000-0000-1234
0000-0000-0123
0000-0001-2345
1234-5678-9012
You can use vsprintf, a much simpler approach
<?php
$no_arr = ['1234', '123', '12345', '123456789012345'];
foreach($no_arr as $n){
echo vsprintf("%04d-%04d-%04d",str_split(sprintf("%012d", $n), 4))."<br/>";
}
Output will be:
0000-0000-1234
0000-0000-0123
0000-0001-2345
1234-5678-9012
Just format the string using sprintf, split it and then implode!
<?php
$no_arr = ['1234', '123', '12345', '123456789012345'];
foreach($no_arr as $n){
$formatted_number = str_split(sprintf("%012d", $n), 4);
echo substr(implode("-", $formatted_number), 0, 14) .'<br>';
}
Output will be:
0000-0000-1234
0000-0000-0123
0000-0001-2345
1234-5678-9012
Explanation:
$twelve_digit = sprintf("%012d", $n);
$split_into_4 = str_split($twelve_digit, 4);
$add_hyphen = implode("-", $split_into_4);
$remove_trailing_chars = substr($add_hyphen, 0, 14);
echo $remove_trailing_chars ." <br/>";
One Liner:
echo substr(implode("-", str_split(sprintf("%012d", $n), 4)), 0, 14);