I was given a quiz by an employer to determine my ability as a programmer and the test was more or less "Write a function that counts the length of this linked list". I failed the quiz because for whatever reason my function didn't return anything (It was a timed quiz). This is my code.
class IntList{
var $value = 1;
var $next = null;
}
$A = new IntList();
$B = new IntList();
$C = new IntList();
$D = new IntList();
$A->next = $B;
$B->next = $C;
$C->next = $D;
main($A);
$count = 0;
function main($L)
{
global $count;
$final = getListLength($L, $count);
print $final;
}
function getListLength($L, $count)
{
if (isset($L->next))
{
$count++;
getListLength($L->next, $count);
} else
{
print $count;
return $count;
}
}
in getListLength im getting 3 when i print count before the return statement. But after the function returns I'm left with no output. I feel really stupid right now. Any thoughts?
Assuming this is the code from the quiz (argh, PHP4 --'):
class IntList{
var $value = 1;
var $next = null;
}
$A = new IntList();
$B = new IntList();
$C = new IntList();
$D = new IntList();
$A->next = $B;
$B->next = $C;
$C->next = $D;
I don't think you need recursion to solve that. You could just:
function getListLength($list) {
$count = 0;
$item = $list;
while($item instanceof IntList) {
$count++;
$item = $item->next;
}
return $count;
}
You just forgot to put global $count; in the second function.
Also, if you want to count the last one, you should move the $count++ outside of the conditional.
Here's a fiddle.
Alternatively, you can pass the $count variable by reference
function getListLength($L, &$count){...}
Another fiddle..
Since you are trying to use recursion here, I think the only thing that is missing is that your recursive case is not returning. You really should not need global. If you need to start at zero, you can give your getListLength a default count, or explicitly call it with zero in main.
function main($L) {
$final = getListLength($L);
print $final;
}
function getListLength($L, $count = 0) {
if (isset($L->next)) {
$count++;
// this case should return
return getListLength($L->next, $count);
} else {
return $count;
}
}
Related
is there any way to check whether array_filter deleted any value from an array?
The solutions I've thought of are these ones:
$sample_array = ["values"];
$array_copy = $sample_array;
if (array_filter($sample_array, 'fn') === $array_copy) {
#Some value was deleted from the array
} else {
#The array was not modified
}
This one doesn't seem very efficient, as it has to copy the entire array.
$sample_array = ["values"];
$array_count = count($sample_array);
if (count(array_filter($sample_array, 'fn')) === $array_count) {
#The array was not modified
} else {
#Some value was deleted from the array
}
This one seems more efficient, though I was wondering if there was a more elegant way of approaching the issue.
Thank you beforehand.
You can extend your function to keep track of the change itself.
$array = [1, 2, 3, 4];
$changed = 0;
$new = array_filter($array, function($e) use (&$changed) {
$result = $e <= 2;
if(!$result) $changed++;
return $result;
});
Returns $changed as 2.
Use array_diff to compare two arrays.
if(array_diff($array_copy, $sample_array))
echo "not same";
Using 'count()' is IMHO the most elegant solution and, I suspect, may be a lot more efficient - you'd need to measure it. OTOH, for your consideration...
function fn($arg, $mode='default')
{
static $matched;
if ('default'==$mode) {
$result=real_filter_fn($arg);
$matched+=$result ? 1 : 0;
return $result;
}
$result=$matched;
$matched=0;
return $result;
}
If you want to keep track of the removed elements, you could do something like this.
$sample_array = ['values', 'test'];
$removed = []; // Contains all the removed values.
$new_array = array_filter($sample_array, function($value) use (&$removed) {
if($value == 'test') {
$removed[] = $value; // Adds the value to the removed array.
return false;
}
return true;
});
print_r($removed);
You could use a closure to change the state of a boolean variable:
$sample_array = [1,2,3,4];
$array_changed = false;
//Use closure to change $array_changed
print_r(array_filter($sample_array, function($var) use (&$array_changed) {
$check = (!($var & 1));
$array_changed = $array_changed?:$check;
return $check;
}));
if ($array_changed) {
#Some value was deleted from the array
} else {
#The array was not modified
}
[EDIT]
This is a simple speedtest of your solutions compared to mine:
/**********************SPEEDTEST**************************/
function fn ($var) {
return (!($var & 1));
}
$sample_array = [1,2,3,4];
$before = microtime(true);
for ($i=0 ; $i<100000 ; $i++) {
$array_changed = false;
//Use closure to change $array_changed
array_filter($sample_array, function($var) use (&$array_changed) {
$check = (!($var & 1));
$array_changed = $array_changed?:$check;
return $check;
});
if ($array_changed) {
#Some value was deleted from the array
} else {
#The array was not modified
}
}
$after = microtime(true);
echo "Using closure: " . ($after-$before)/$i . " sec/run\n";
echo '<br>';
/*******************************************************/
$before = microtime(true);
for ($i=0 ; $i<100000 ; $i++) {
$array_copy = $sample_array;
if (array_filter($sample_array, 'fn') === $array_copy) {
#Some value was deleted from the array
} else {
#The array was not modified
}
}
$after = microtime(true);
echo "Using array copy: " . ($after-$before)/$i . " sec/run\n";
echo '<br>';
/*******************************************************/
$before = microtime(true);
for ($i=0 ; $i<100000 ; $i++) {
$array_count = count($sample_array);
if (count(array_filter($sample_array, 'fn')) === $array_count) {
#The array was not modified
} else {
#Some value was deleted from the array
}
}
$after = microtime(true);
echo "Using array count: " . ($after-$before)/$i . " sec/run\n";
The results:
Using closure: 9.1402053833008E-7 sec/run
Using array copy: 4.9885988235474E-7 sec/run
Using array count: 5.5881977081299E-7 sec/run
Maybe that helps with decision-making :)
Let's say I want to check for simple mathematical progression. I understand I can do it like this:
if ($a<$b and $b<$c and $c<$d and $d<$e and $e<$f) { echo OK; }
Is there a way to do it in a more convenient way? Like so
if ($a..$f isprog(<)) { echo OK; }
I don 't know if I get your problem right. But propably the solution for your progression could be the SplHeap object of the SPL delivered with php.
$stack = new SplMaxHeap();
$stack->insert(1);
$stack->insert(3);
$stack->insert(2);
$stack->insert(4);
$stack->insert(5);
foreach ($stack as $value) {
echo $value . "\n";
}
// output will be: 5, 4, 3, 2, 1
I havent heard of something like this, but how about using simple function:
function checkProgress($vars){ //to make it easie i assume that vars can be given in an array
$result = true;
for ($i=0; $i<= count($vars); $i++){
if ($i>0 && $vars[$i] > $vars[$i-1]) continue;
$result = false;
}
return $result;
}
Solved it quick and dirty:
function ispositiveprogression($vars) {
$num=count($vars)-1;
while ($num) {
$result = true;
if ($vars[$num] > $vars[$num-1]) {
$num--;
}
else { $result = false; break; }
}
return $result;
}
Create an array of values, iterate over them and maintaining a flag that checks if the current element value is greater than / less than that of the next value. Unlike some of the solutions in this thread, this doesn't loop through the whole array. It stops looping when it discovers the first value that's not a progression. This will be a lot more faster if the operation involves a lot of numbers.
function checkIfProg($arr, $compare) {
$flag = true;
for ($i = 0, $c = count($arr); $i < $c; $i++) {
if ($compare == '<') {
if (isset($arr[$i + 1]) && $arr[$i] > $arr[$i + 1]) {
$flag = false;
break;
}
} elseif ($compare == '>') {
if (isset($arr[$i + 1]) && $arr[$i] < $arr[$i + 1]) {
$flag = false;
break;
}
}
}
return $flag;
}
Usage:
$a = 2;
$b = 3;
$c = 4;
$d = 5;
$e = 9;
$f = 22;
$arr = array($a, $b, $c, $d, $e, $f);
var_dump(checkIfProg($arr, '<')); // => bool(true)
If you want the array to be created dynamically, you could use some variable variable magic to achieve this:
$arr = array();
foreach (range('a','f') as $v) {
$arr[] = $$v;
}
This will create an array containing all the values of variables from $a ... $f.
My code:
$a['page'] = 1;
function change($a) {
$a['page'] = 2;
}
My output:
$a['page'] = 1;
$a['page'] = 2;
Why am I get two keys 'page'?
I was expecting the function changed the value.
you could pass $a by reference instead and it would work as expected. It would be slower but not significantly so, given the function.
$a['page'] = 1;
function change(&$a) {
$a['page'] = 2;
}
change($a);
echo "<pre>";
print_r($a);
$a['page'] = 1;
function change($a) {
return $a['page'] = 2;
}
echo change($a);
Write a class called math. It is to have one property called num. It also has one method (function) called factorial. This method is to start at 1 and multiply all of the integers to num. If num is 5 then you would multiply 1*2*3*4*5. Of course you are to do this in a loop.
Which loop should I use? For or do while? Also, do I need an inner loop?
I started with
For (i = 1; i <= 5; i++)
{
}
however, i'm stuck on what to do next...any suggestions?
You can do it using any loop. for loop can be converted to while and do .. while and opposite is true too.
for(i=0;i<5;i++)
is same as
i=0; while(i<5){i++;}
To to find the factorial you should multiply all the values from 1 to the number you want factorial of. So if $num = 5. Only one single loop is needed. You'd want to run this loop.
for($i=1;$i<$num;$i++){
$num*=$i;
}
I am not giving a full solution here because the question seems homework. If I give you full solution it will be spoon-feeding.
$result = 1;
$target = 5;
for ($i = 1;$ i <= $target; $i++)
{
$result *= $i;
}
echo $result;
or
$result = 1;
$target = 5;
while($target > 0) {
$result *= $target;
$target--; // You could do this all in one line, but for learners, this is clearer.
}
echo $result;
Each iteration you will want to multiply the total of the factorial by the value of $i
class Math {
public static function Factorial($factorial) {
$output = 1;
for($i = 2; $i <= $factorial; $i++)
$output *= $i;
return $output;
}
}
I've gotten to where I prefer the while(i--) loop:
<?php
class Math {
public $num = 0;
public function factorial() {
$result = 1;
$num = $this->num;
while ($num) {
$result *= $num--;
}
return $result;
}
}
$factor = new Math();
$factor->num = 5;
echo $factor->factorial();
?>
http://codepad.org/hUOgAoz2
Is it possible to execute a function, then return a new value for Var and therefore when it tries to loop again it checks the condition and detects the changes?
Let's say I have this function:
function changeZ(){
$z=1
return $z;
}
and this is my while loop:
$a = 0;
$z = 10;
while($a<$z){
changeZ();
$a++;
}
How should I modify the codes such that
the function changeZ() returns a new value for the variable $z
and therefore when the loop checks for condition (1<1), it returns a false and stop looping.
You can pass by reference or return the value
$z = 100;
change($z);
function change(&$var) {
$var = 1;
}
$z = 100;
$z = change($z);
function change($var) {
return $var * 100 - 50;// Logic with $z obviously can be whatever
}
The $z in your function and the $z you use in the loop are not the same guys. So you have to set the value of the loop-z to the return value of your function...
$a = 0;
$z = 10;
while($a<$z){
$z = changeZ();
$a++;
}
$z = changeZ();
but as commented, you appear to definitely going about this wrong.
$a = 0;
$z = 10;
while($a<$z){
$z = changeZ();
$a++;
}
Since your function returns a value you should set your variable to contain the returned value. This will do what you asked resulting in the loop running only once.
Another thing you can do is pass the variable into a function like so
function changeZ($in){
$out = $in-1;
return $out;
}
$a = 0;
$z = 10;
while($a<$z){
$z = changeZ($z);
$a++;
}
This will result in the loop running 5 times as one number goes up the other goes down
0<10
1<9
2<8
3<7
4<6
you can use this for your purpose for storing the returned data from function into an array.
function changeZ(){
$z = $row['result']; //your data from database
return $z;
}
$a = 0;
$z = 10;
$returned_value=new array();
while($a<$z){
$returned_value[] = changeZ();
$a++;
}
You have to put this
$a = 0;
$z = 10;
while($a<$z) {
$z = changeZ();
$a++;
}