I am trying to make it so that my code displays if entered array of numbers can be divided into 2 groups, and if yes then it displays"yes" or if no then"no. The yes or no part works fine, but if the code says yes then I want the code to also display the 2 columns with the numbers, I tried a lot but I just can't figure it out, please help.
function helper(&$arr, $n, $start, $lsum, $rsum) {
if ($start == $n)
return $lsum == $rsum;
if ($arr[$start] % 5 == 0)
$lsum += $arr[$start];
else if ($arr[$start] % 3 == 0)
$rsum += $arr[$start];
else
return helper($arr, $n, $start + 1, $lsum + $arr[$start], $rsum)
|| helper($arr, $n, $start + 1, $lsum, $rsum + $arr[$start]);
return helper($arr, $n, $start + 1, $lsum, $rsum);
}
function splitArray($arr, $n) {
return helper($arr, $n, 0, 0, 0);
}
$arr = array( 7,1, 7,3,4,6);
$n = count($arr);
if (splitArray($arr, $n))
print("Yes");
else
print("No");
Provided you want to split them into two parts
Replace your code at the bottom with...
$arr = array( 7,1, 7,3,4,6);
$n = count($arr);
list($group1, $group2) = array_chunk($arr, ceil(count($arr) / 2)); //Split the initial array into 2 if you want 3 just change 2 to 3 and so forth
if (splitArray($arr, $n)){
echo "Yes";
print_r($group1);
print_r($group2); //Each array assigned to new variable
} else {
echo "No";
}
Related
I try to recreate what we see when we printing page on office or adobe.
For example, when you want to print page 1 to 5 you write : 1-5 and if you want to print a page outside you write : 1-5,8
At the moment I explode string by ',' :
1-5 / 8
Then explode each result by '-' and if I've got result I loop from first page to last and create variable with comma :
1,2,3,4,5,8
Finally I explode by ',' and use array unique to erase double value.
It take some times to achieve this especially when there's a lot of '-'.
Maybe someone got a easier solution to so this ?
Thank
Edit :
$pages = "1-4,6-8,14,16,18-20";
$pages_explode = explode(',',$pages);
foreach($pages_explode as $page){
$page_explode = explode('-',$page);
if(!empty($page_explode[1])){
for ($i=$page_explode[0]; $i<=$page_explode[1] ; $i++) {
$page_final .= $i.',';
}
}else{
$page_final .= $page_explode[0].',';
}
}
$page_final = explode(',',$page_final);
$page_final = array_unique ($page_final);
foreach($page_final as $value){
echo $value.'<br>';
}
Is it a code golf challenge?
Well a basic approach seems fine to me :
$input = '1-5,6-12,8';
$patterns = explode(',', $input);
$pages = [];
foreach ($patterns as $pattern) {
if (2 == count($range = explode('-', $pattern))) {
$pages = array_merge($pages, range($range[0], $range[1]));
} else {
$pages[] = (int)$pattern;
}
}
$uniquePages = array_unique($pages);
var_dump($uniquePages);
Outputs :
array (size=12)
0 => int 1
1 => int 2
2 => int 3
3 => int 4
4 => int 5
5 => int 6
6 => int 7
7 => int 8
8 => int 9
9 => int 10
10 => int 11
11 => int 12
Having to remove duplicates suggests that you have overlapping ranges in your strings.
Eg: 1-5,2-9,7-15,8,10
You seems to process all these without considering the overlapping areas and finally attempt to remove duplicates by the expensive array_unique function.
Your code should instead remember the minimum and maximum of the resulting range and not process anything that overlaps this range.
Following is a sample code which demonstrates the idea. But its certainly faster than the code you have suggested in your question. You should add parts there to process additional types of delimiters, if any, in your requirement.
<?php
$ranges = "1-5,3-7,6-10,8,11";
$min = 10000;
$max = -1;
$numbers = array(); //Your numbers go here
//Just a utility function to generate numbers from any range and update margins
function generateNumbers($minVal, $maxVal) {
global $min, $max, $numbers;
for ($i = $minVal; $i <= $maxVal; $i++) {
array_push($numbers, $i);
if ($i < $min)
$min = $i;
if ($i > $max)
$max = $i;
}
}
//Seperate ranges
$sets = explode(",", $ranges);
//Go through each range
foreach($sets as $aSet) {
//Extract the range or get individual numbers
$range = explode("-", $aSet);
if (count($range) == 1) { //its an individual number. So check margins and insert
$aSet = intval($aSet);
if ($aSet < $min){
array_push($numbers, $aSet);
$min = $aSet;
}
if ($aSet > $max){
array_push($numbers, $aSet);
$max = $aSet;
}
continue; // <----- For single numbers it ends here
}
//Its a range
$rangeLow = intval($range[0]);
$rangeHigh = intval($range[1]);
//Adjusting numbers to omit cases when ranges fall right on the margins
if ($rangeLow == $min){
$rangeLow++;
}
else
if ($rangeLow == $max) {
$rangeLow--;
}
if ($rangeHigh == $min){
$rangeHigh++;
}
else
if ($rangeHigh == $max) {
$rangeHigh--;
}
//Check if below or above the generated range
if (($rangeLow < $min && $rangeHigh < $min) || ($rangeLow > $max && $rangeHigh > $max)) {
generateNumbers($rangeLow, $rangeHigh);
};
//Check if across the lower edge of the generated range
if ($rangeLow < $min && $rangeHigh > $min && $rangeHigh < $max) {
generateNumbers($rangeLow, $min - 1);
};
//Check if across the upper edge of the generated range
if ($rangeLow > $min && $rangeLow < $max && $rangeHigh > $max) {
generateNumbers($max + 1, $rangeHigh);
};
}
//Now just sort the array
print_r($numbers);
?>
I have a large number that I want to split in half. For this example, let's use: 5639445604728832
When it is split in half it comes out like this:
56394456
04728832
Obviously, the second number isn't a number anymore.
I have the following code, but I am trying to make it so it will add the 0's to the end of the first number until the second number is officially a real number. Could anyone help me solve this?
function my_number_split($number)
{
$half = (int) ( (strlen($number) / 2) ); // cast to int incase str length is odd
$left = substr($number, 0, $half);
$right = substr($number, $half);
echo $left."<br />".$right;
}
Rewriting your function like this would do the trick.
function my_number_split($number)
{
$half = ceil( (strlen($number) / 2) );
while (0 == substr($number, $half, 1) && $half <= strlen($number) ) $half++;
$left = substr($number, 0, $half);
$right = substr($number, $half);
echo $left."<br />".$right;
}
Simple loop should do it.
Something like this -
function my_number_split($number)
{
/* Logic to traverse ahead till a 0 is not found. */
$str_len = strlen($number);
$half_index = $str_len/2;
while($half_index < $str_len){
if($number[$half_index] != "0"){
break;
}
$half_index++;
}
//Slicing string.
$left = substr($number, 0, $half_index);
$right = substr($number, $half_index);
echo $left."<br />".$right;
}
my_number_split("5639445604728832");
/*
OUTPUT -
563944560
4728832
*/
It's probably an inefficient way, but for the challenge:
if (preg_match('~\A(?<n1>.?(?:.(?=.*(.(?(2)\2)\z)))+0*)(?<n2>.+)~', $number, $m))
echo $m['n1'] . "\n" . $m['n2'];
I have the following code:
for($a=1; $a<strlen($string); $a++){
for($b=1; $a+$b<strlen($string); $b++){
for($c=1; $a+$b+$c<strlen($string); $c++){
for($d=1; $a+$b+$c+$d<strlen($string); $d++){
$tempString = substr_replace($string, ".", $a, 0);
$tempString = substr_replace($tempString, ".", $a+$b+1, 0);
$tempString = substr_replace($tempString, ".", $a+$b+$c+2, 0);
$tempString = substr_replace($tempString, ".", $a+$b+$c+$d+3, 0);
echo $tempString."</br>";
}
}
}
}
What it does is to make all possible combinatons of a string with several dots.
Example:
t.est123
te.st123
tes.t123
...
test12.3
Then, I add one more dot:
t.e.st123
t.es.t123
...
test1.2.3
Doing the way I'm doing now, I need to create lots and lots of for loops, each for a determined number of dots. I don't know how I can turn that example into a functon or other easier way of doing this.
Your problem is a combination problem. Note: I'm not a math freak, I only researched this information because of interest.
http://en.wikipedia.org/wiki/Combination#Number_of_k-combinations
Also known as n choose k. The Binomial coefficient is a function which gives you the number of combinations.
A function I found here: Calculate value of n choose k
function choose($n, $k) {
if ($k == 0) {return 1;}
return($n * choose($n - 1, $k - 1)) / $k;
}
// 6 positions between characters (test123), 4 dots
echo choose(6, 4); // 15 combinations
To get all combinations you also have to choose between different algorithms.
Good post: https://stackoverflow.com/a/127856/1948627
UPDATE:
I found a site with an algorithm in different programming languages. (But not PHP)
I've converted it to PHP:
function bitprint($u){
$s= [];
for($n= 0;$u > 0;++$n, $u>>= 1) {
if(($u & 1) > 0) $s[] = $n;
}
return $s;
}
function bitcount($u){
for($n= 0;$u > 0;++$n, $u&= ($u - 1));
return $n;
}
function comb($c, $n){
$s= [];
for($u= 0;$u < 1 << $n;$u++) {
if(bitcount($u) == $c) $s[] = bitprint($u);
}
return $s;
}
echo '<pre>';
print_r(comb(4, 6));
It outputs an array with all combinations (positions between the chars).
The next step is to replace the string with the dots:
$string = 'test123';
$sign = '.';
$combs = comb(4, 6);
// get all combinations (Th3lmuu90)
/*
$combs = [];
for($i=0; $i<strlen($string); $i++){
$combs = array_merge($combs, comb($i, strlen($string)-1));
}
*/
foreach ($combs as $comb) {
$a = $string;
for ($i = count($comb) - 1; $i >= 0; $i--) {
$a = substr_replace($a, $sign, $comb[$i] + 1, 0);
}
echo $a.'<br>';
}
// output:
t.e.s.t.123
t.e.s.t1.23
t.e.st.1.23
t.es.t.1.23
te.s.t.1.23
t.e.s.t12.3
t.e.st.12.3
t.es.t.12.3
te.s.t.12.3
t.e.st1.2.3
t.es.t1.2.3
te.s.t1.2.3
t.est.1.2.3
te.st.1.2.3
tes.t.1.2.3
This is quite an unusual question, but I can't help but try to wrap around what you are tying to do. My guess is that you want to see how many combinations of a string there are with a dot moving between characters, finally coming to rest right before the last character.
My understanding is you want a count and a printout of string similar to what you see here:
t.est
te.st
tes.t
t.es.t
te.s.t
t.e.s.t
count: 6
To facilitate this functionality I came up with a class, this way you could port it to other parts of code and it can handle multiple strings. The caveat here is the strings must be at least two characters and not contain a period. Here is the code for the class:
class DotCombos
{
public $combos;
private function combos($string)
{
$rebuilt = "";
$characters = str_split($string);
foreach($characters as $index => $char) {
if($index == 0 || $index == count($characters)) {
continue;
} else if(isset($characters[$index]) && $characters[$index] == ".") {
break;
} else {
$rebuilt = substr($string, 0, $index) . "." . substr($string, $index);
print("$rebuilt\n");
$this->combos++;
}
}
return $rebuilt;
}
public function allCombos($string)
{
if(strlen($string) < 2) {
return null;
}
$this->combos = 0;
for($i = 0; $i < count(str_split($string)) - 1; $i++) {
$string = $this->combos($string);
}
}
}
To make use of the class you would do this:
$combos = new DotCombos();
$combos->allCombos("test123");
print("Count: $combos->combos");
The output would be:
t.est123
te.st123
tes.t123
test.123
test1.23
test12.3
t.est12.3
te.st12.3
tes.t12.3
test.12.3
test1.2.3
t.est1.2.3
te.st1.2.3
tes.t1.2.3
test.1.2.3
t.est.1.2.3
te.st.1.2.3
tes.t.1.2.3
t.es.t.1.2.3
te.s.t.1.2.3
t.e.s.t.1.2.3
Count: 21
Hope that is what you are looking for (or at least helps)....
How can I calculate the n-th root of an integer using PHP/GMP?
Although I found a function called gmp_root(a, nth) in the PHP source, it seems that this function has not been published in any release yet*: http://3v4l.org/8FjU7
*) 5.6.0alpha2 being the most recent one at the time of writing
Original source: Calculating Nth root with bcmath in PHP – thanks and credits to HamZa!
I've rewritten the code to use GMP instead of BCMath:
function gmp_nth_root($num, $n) {
if ($n < 1) return 0; // we want positive exponents
if ($num <= 0) return 0; // we want positive numbers
if ($num < 2) return 1; // n-th root of 1 or 2 give 1
// g is our guess number
$g = 2;
// while (g^n < num) g=g*2
while (gmp_cmp(gmp_pow($g, $n), $num) < 0) {
$g = gmp_mul($g, 2);
}
// if (g^n==num) num is a power of 2, we're lucky, end of job
if (gmp_cmp(gmp_pow($g, $n), $num) == 0) {
return $g;
}
// if we're here num wasn't a power of 2 :(
$og = $g; // og means original guess and here is our upper bound
$g = gmp_div($g, 2); // g is set to be our lower bound
$step = gmp_div(gmp_sub($og, $g), 2); // step is the half of upper bound - lower bound
$g = gmp_add($g, $step); // we start at lower bound + step , basically in the middle of our interval
// while step != 1
while (gmp_cmp($step, 1) > 0) {
$guess = gmp_pow($g, $n);
$step = gmp_div($step, 2);
$comp = gmp_cmp($guess, $num); // compare our guess with real number
if ($comp < 0) { // if guess is lower we add the new step
$g = gmp_add($g, $step);
} else if ($comp == 1) { // if guess is higher we sub the new step
$g = gmp_sub($g, $step);
} else { // if guess is exactly the num we're done, we return the value
return $g;
}
}
// whatever happened, g is the closest guess we can make so return it
return $g;
}
I am making an ajax call in jquery
$.get("validate_isbn.php", {isbn: obj[16]},
function(answer)
{
console.log(answer);
if (answer == "valid")
{
var checked1 = $(elements[index]).val();
//$(elements[index]).val().append("<img src = 'pics/green_checkmark.png'>"); //doesn't work
//elements.after("<img src = 'pics/green_checkmark.png'>"); //sets all the elements with this pic
elements.eq(index).after("<img src='pics/green_checkmark.png' id='checkmark'>");
var checked = $(elements[index]).val();
}
});
which worked fine. I saw in the debugger that it was properly sending over the variable isbn with a isbn number from the obj array. My problem is on the php side. When I was testing, I simply had the code echo "valid" and everything worked out fine. But now when I put the real code in it stopped working:
<?php
//This algorithm is for ISBN 10
function is_isbn_10_valid($n){
$check = 0;
for ($i = 0; $i < 9; $i++)
{
$check += (10 - $i) * substr($n, $i, 1); //starting at the leftmost digit, multiple each digit by a constant, starting at 10, add the total
}
$t = substr($n, 9, 1); // tenth digit (aka checksum or check digit)
$check += ($t == 'x' || $t == 'X') ? 10 : $t; //now add the tenth digit
return $check % 11 == 0;
}
//The algorithm for ISBN 13 validation is as follows:
//Multiply each digit of teh isbn, starting at the left, with 1,3,3... etc for the entire isbn (including the check digit becuase its
//just going to be multiplied by 1 anyways.
//Add them all together, do mod 10 and voila!
function is_isbn_13_valid($n){
$check = 0;
for ($i = 0; $i < 13; $i+=2) //this does digits 1,3,5,7,9,10,11,13
{
$check += substr($n, $i, 1);
}
for ($i = 1; $i < 12; $i+=2) //this does digits 2,4,6,8,10,12
{
$check += 3 * substr($n, $i, 1);
}
return $check % 10 == 0;
}
$isbn = $_GET["isbn"];
if (strlen($isbn) = 10)
{
$result = is_isbn_10_valid($isbn);
}
else if (strlen($isbn) = 13)
{
$result = is_isbn_13_valid($isbn);
}
else
{
$result false;
}
if ($result === true)
{echo "valid";}
else if ($result === false)
{echo "not valid";}
?>
(Note: I'm sure that I can be more efficient and just return the boolean, but I refrained from that at the moment since I wasn't sure how the jquery .get would take it, as a boolean or text...)
Anyways, it doesn't work. The error on the console.log gives me:
Fatal error: Can't use function return value in write context in ...pathname here...\validate_isbn.php on line 31
On line 31, you have this:
if ($strlen($isbn) = 10)
Remove the $ on the strlen function, and change the = (assignment operator) to a == (equivalence operator). It should now look like this:
if (strlen($isbn) == 10)
You'll need to do the same a few lines after that, too.
Edit: One more thing. About five lines from the bottom, you're missing an equal sign.
$result false;
Should be:
$result = false;