Php recursion of a tree of comments, with global variable - php

<?php
tree($Comments, 0, 0);
$var = -1;
function tree($Comments, $parent_id = 0, $level=0) {
global $var;
foreach($Comments as $Comment){
if($Comment['parent_id'] == $parent_id) {
If ($level > $var) {$var++;} else {echo ($var-$level+1); $var=$level;};
for ($i=$level; $i>0; $i--)
echo "-";
echo $Comment['text']."<br>";
tree($Comments, $Comment['id'], $level+1);
}
}
}
?>
This is my recursive method of displaying the tree of comments(thread comments),
the problem is I have to make, in that (if ($level > $var) statement get variable $var of how many (</div> for a bootstrap design) I should use for making the design for the comment threads. The problem is that I get first result 1, which supposedly I shouldn't, the rest gets as It should have to.
Edit 1, Example of data in database(to easy understand):
id id_theme parent_id user text
16 14 0 DomainFlag This is 1!
17 14 16 DomainFlag This is 2!
18 14 16 DomainFlag This is 3!
20 14 17 DomainFlag This is 4!
21 14 17 DomainFlag This is 5!
22 14 21 DomainFlag This is 7!
23 14 22 DomainFlag This is 8!
24 14 18 DomainFlag This is 6!
25 14 0 DomainFlag This is 9!
26 14 25 DomainFlag This is 10!
27 14 25 DomainFlag This is 11!
My table:
id
parent_id
id_theme
user
text
upVotes
downVotes
My idea is to make a threaded system of comments like(with $level which I get from the recursive function):
0
1
2
3
2
1
1
0
1
0
So I get this result with that 1 at first no matter what, which I shouldn't( 1 This is 1!). The rest is working perfectly.
1This is 1!
-This is 2!
--This is 4!
1--This is 5!
---This is 7!
----This is 8!
4-This is 3!
--This is 6!
3This is 9!
-This is 10!
1-This is 11!
Why that 1 at the beginning appears? I heard that global scopes isn't good to implement, why? and what I should do to not use it?

Related

Get value of multidimensional array in array

I have below values in formsubmit,
items[0][item_name]: Test
items[0][item_description]: testing1
items[0][item_price]: 11
items[0][item_group]: 18
items[0][item_code]: 11
items[0][item_is_active][]: 1
items[1][item_name]: test2
items[1][item_description]: test
items[1][item_price]: 12
items[1][item_group]: 18
items[1][item_code]: 12
items[1][item_is_active][]: 1
and here is serverside DB entry in laravel,
$items_data = $request->items;
foreach ($items_data as $i) {
$items = new Menuitems; //Must be reinit to reiterate all entries
$items->item_name = $i['item_name'];
$items->item_description = $i['item_description'];
$items->item_price = $i['item_price'];
$items->item_group = $i['item_group'];
$items->item_code = $i['item_code'];
$items->item_is_active = $i['item_is_active'];
$items->save();
}
It works fine all entries except for item_is_active because it has one more [ ] in form input,
How can I add item_is_active in foreach loop? should it have one more foreach loop inside?
Below is formsubmit values when some checkboxes are not selected,
items[0][item_name]: Capachno
items[0][item_description]: best
items[0][item_price]: 12
items[0][item_group]: 17
items[0][item_code]: 11
items[0][item_is_active][]: 1
items[1][item_name]: Lambc
items[1][item_description]: sdf
items[1][item_price]: 34
items[1][item_group]: 17
items[1][item_code]: 12
items[1][item_is_active][]: 1
items[2][item_name]: tasto
items[2][item_description]: ewr
items[2][item_price]: 12
items[2][item_group]: 17
items[2][item_code]: 13
items[3][item_name]: hingo
items[3][item_description]: 123
items[3][item_price]: 123
items[3][item_group]: 17
items[3][item_code]: 32

Mapping Values to 14 categories (Math and permutations stuff)

My app has people put 24 groups of 4 statements in order. In each group of 4 one is the "D" statement, one is the "I" statement, one is the "S" statement, and one is the "C" statement.
So the end result looks something like ['ISCD','CISD','DISC',CISD,'CISD','ISCD'...] because the are essentially rearranging the 4 letters
In the end, they get a "score" for each letter using the following algorithm.
For each of I,S,C and D
Find the number of times that letter is first and multiply by 3
Find the number of times that letter is second and multiply by 2
Find the number of times that letter is third and muliply by 1
Total it up, and that is the score for that letter
The end result is that each letter (I,S,D,C) gets a score from 0 to 72, and there are always 144 total points given out:
I want to map the results to 14 reports:
D
I
S
C
DI
IS
SC
CD
DS
IC
DIS
ISC
SCD
CDI
The idea is that if S is dominant, we choose the S report. If Both D and I are dominant, we choose the DI report. If none is particularly dominant, we choose the top 3. (there is no difference between DI and ID meaning which one is most dominant is irrelevant if they are both high)
So if the scores are D=50, I=48, S=20,C=26 then I want it to choose "DI" since D and I are dominant. There are 24^(4!) possible responses from the user, that I need to map to 14 reports
I understand that I will have to set the thresholds for what "dominant" means, but for starters, I want to assume all possible responses are equally likely, and to map all possible responses to the 14 reports to where each of the 14 reports is equally likely, given random input.
I expect it's 1 to 5 lines of code. It'll be in php but any language including math or pseudo code should be fine.
UPDATE:
I figured out a way to do it in one line of code, but it's not evenly distributed. here's the php (no dependencies)
<?php
$totals=array();
$lets=array('D','I','S','C');
for($j=0;$j<100000;$j++)
{
$vals=array('D'=>0,'I'=>0,'S'=>0,'C'=>0);
for($i=0;$i<24;$i++)
{
shuffle($lets);
$vals[$lets[0]]+=3;
$vals[$lets[1]]+=2;
$vals[$lets[2]]+=1;
}
$D=$vals['D'];$I=$vals['I'];$S=$vals['S'];$C=$vals['C'];
//calculate which report
$reportKey=($D>36?'D':'').($I>36?'I':'').($S>36?'S':'').($C>36?'C':'');
if(!$reportKey)
$reportKey="DIS";
if(isset($totals[$reportKey]))
$totals[$reportKey]+=1;
else
$totals[$reportKey]=1;
echo $reportKey." $D $I $S $C <br>";
}
echo "<br>";
foreach ($totals as $k=>$v)
echo "$k: $v<br>";
The magic line is
$reportKey=($D>36?'D':'').($I>36?'I':'').($S>36?'S':'').($C>36?'C':'');
That line says if any value is over 36, include that letter. the output of the script is like this:
SC 35 33 38 38
IC 33 42 32 37
DI 44 39 29 32
...
...
DC 46 21 35 42
DIS 38 37 40 29
IC 36 39 28 41
DS 41 36 42 25
C 36 34 29 45
IS 29 41 38 36
IS 28 46 41 29
DS 38 33 40 33
DS 41 33 40 30
DS: 1444
D: 889
IS: 1466
S: 910
C: 874
SC: 1442
IC: 1467
DI: 1569
ISC: 407
DSC: 386
DIS: 388
DC: 1487
DIC: 396
I: 875
As you can see, it automatically split it into 14 categories, but the distribution varies with the 2 letter ones being way more likely.
You can do this recursively using Haskell e.g. as follows:
combinationsOf _ 0 = [[]]
combinationsOf [] _ = []
combinationsOf (x:xs) k = map (x:) (combinationsOf xs (k-1) ) ++ combinationsOf xs k
The results from GHCI:
*Main> concatMap (combinationsOf "DISC") [1,2,3]
["D","I","S","C","DI","DS","DC","IS","IC","SC","DIS","DIC","DSC","ISC"]

proper arrangement in foreach

$random = rand(4, 23);
$range = range(1, $random );
HI.. guys
I have a random range value here in foreach function i want to display with below
rules.. my aim is to display like a square box
if i get range 1 to 3 it has to display table like this
1 2
3
if range from 1 to 6
1 2 3
4 5 6
if range from 1 to 19
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19
get the ceil of the square root of the number of records, and then anytime you're at an index with a mod of that value that is equal to 0, start a new line. Since you already have $random something like:
$dim = ceil(sqrt($random));
foreach ($range as $index => $number) {
print $number;
if (!(($index + 1) % $dim)) {
print "\n";
}
else {
print " ";
}
}
May need some adjustment (I'm not in PHP mode atm) and also doesn't factor in the padding but that should be straightforward.

php format input data and put it into multiple arrays

i'm trying to put input (below) into multiple arrays (or maybe its simpler into one array) to finally export it into mysql table, input data goes like:
0 98
77 09
0 12
0 98234
32 0
0 1
0 0
345 32
34 9
6437 34
789 0
0 0
.
.
34 0
my simple code ($run_txt_filter1 is input):
if ( $counted == 64)
{
echo "line's number: ".$counted;
//echo $run_txt_filter1;
for ($modi = 0; $modi <= 15; $modi++)
{
for ($simhi = 1; $simhi <= 4 ; $simhi++)
{
$exploded=explode(" ", $run_txt_filter1);
var_dump($exploded)." \n";
}
}
}
Why var_dump keeps saying the id from 0-64 ? (there always should be 64 input lines).
What a really want to achieve is:
array0=(0, 77, 0, 0)
array1=(98, 09, 12, 98234)
array2=(32, 0, 0, 345)
.
.
array30=(0, 12, 0, 34)
array31=(0, 0, 0, 0)
thanks in advance
try to separate your explode for the next line and explode for the white space. cause on your code above it's reading the whole string as one causing your program to store it on a single array. so it would be a nested loop by then. :)
Considering this input:
$in = <<<IN
0 98
77 09
0 12
0 98234
32 0
0 1
0 0
345 32
34 9
6437 34
789 0
0 0
IN;
This algorithm solves your problem i think:
$final_array = array();
$offset = 0;
foreach(preg_split("/(\r?\n){2,}/",$in) as $block){
foreach(preg_split("/(\r?\n)/",$block) as $line){
foreach(preg_split("/\s+/",$line) as $column => $value){
if($value=='') continue;
if(!isset($final_array[$offset+$column]))
$final_array[$offset+$column] = array();
$final_array[$offset+$column][]=$value;
}
}
$offset = count($final_array);
}
print_r($final_array);
try something similar to this one I'm not sure if this would work:
inputs:
$inputs = "0 98
77 09
0 12
0 98234
32 0
0 1
0 0
345 32
34 9
6437 34
789 0
0 0
.
.
34 0";
code:
$run_txt_filter1 = explode("\n", $inputs);
if(count($run_txt_filter1) == 64)
{
foreach($run_txt_filter1 as $input)
{
$exploded = explode(' ', $input);
print_r($exploded);
}
}
The "\n" is the next line for windows but it's different on linux its "\r" I'm not sure if it would work you may also try the combination as
explode("\r\n", $inputs);
but just a try if the next line won't work I think you could use some other way to separate each set of values either user other type of characters like ',',';',':' etc. :)

How to Make PHP Faster: Does String Creation Have No Cost?

In this question a code bit is presented and the questioner wants to make it faster by eliminating the use of variables. Seems to me he's looking in the wrong place, but far be it from me to know. Here's the code
while ($item = current($data))
{
echo '<ATTR>',$item, '</ATTR>', "\n";
next($data);
}
Seems to me that the recreation of the strings <ATTR> etc. -- more than once on each line and every time the line is processed -- would have a cost associated with them (both in terms of speed and memory). Or perhaps the PHP processor smart enough so that there's no penalty to not putting the strings into variables before the loop?
I use variables for clarity and centralization in any case, but: is there a cost associated with using variables, not using variables, or what? (Anybody who wants to answer for other similar languages please feel free.)
If you really want to micro-optimize this way (I don't think it is that relevant or useful, btw -- but I understand it's fun ^^ ), you can have a look at a PHP extension called Vulcan Logic Disassembler
It allows you to get the bytecode generated for a PHP script.
Then, you must use a command like this one, in command line, to launch the script :
php -dextension=vld.so -dvld.active=1 tests/temp/temp.php
For instance, with this script :
$data = array('a', 'b', 'c', 'd');
while ($item = current($data))
{
echo '<ATTR>',$item, '</ATTR>', "\n";
next($data);
}
You will get this bytecode dump :
line # op fetch ext return operands
-------------------------------------------------------------------------------
8 0 EXT_STMT
1 INIT_ARRAY ~0 'a'
2 ADD_ARRAY_ELEMENT ~0 'b'
3 ADD_ARRAY_ELEMENT ~0 'c'
4 ADD_ARRAY_ELEMENT ~0 'd'
5 ASSIGN !0, ~0
9 6 EXT_STMT
7 EXT_FCALL_BEGIN
8 SEND_REF !0
9 DO_FCALL 1 'current'
10 EXT_FCALL_END
11 ASSIGN $3 !1, $2
12 JMPZ $3, ->24
11 13 EXT_STMT
14 ECHO '%3CATTR%3E'
15 ECHO !1
16 ECHO '%3C%2FATTR%3E'
17 ECHO '%0A'
12 18 EXT_STMT
19 EXT_FCALL_BEGIN
20 SEND_REF !0
21 DO_FCALL 1 'next'
22 EXT_FCALL_END
13 23 JMP ->7
37 24 RETURN 1
25* ZEND_HANDLE_EXCEPTION
And with this script :
$data = array('a', 'b', 'c', 'd');
while ($item = current($data))
{
echo "<ATTR>$item</ATTR>\n";
next($data);
}
You will get :
line # op fetch ext return operands
-------------------------------------------------------------------------------
19 0 EXT_STMT
1 INIT_ARRAY ~0 'a'
2 ADD_ARRAY_ELEMENT ~0 'b'
3 ADD_ARRAY_ELEMENT ~0 'c'
4 ADD_ARRAY_ELEMENT ~0 'd'
5 ASSIGN !0, ~0
20 6 EXT_STMT
7 EXT_FCALL_BEGIN
8 SEND_REF !0
9 DO_FCALL 1 'current'
10 EXT_FCALL_END
11 ASSIGN $3 !1, $2
12 JMPZ $3, ->25
22 13 EXT_STMT
14 INIT_STRING ~4
15 ADD_STRING ~4 ~4, '%3CATTR%3E'
16 ADD_VAR ~4 ~4, !1
17 ADD_STRING ~4 ~4, '%3C%2FATTR%3E%0A'
18 ECHO ~4
23 19 EXT_STMT
20 EXT_FCALL_BEGIN
21 SEND_REF !0
22 DO_FCALL 1 'next'
23 EXT_FCALL_END
24 24 JMP ->7
39 25 RETURN 1
26* ZEND_HANDLE_EXCEPTION
(This ouput is with PHP 5.2.6, which is the default on Ubuntu Jaunty)
In the end , you will probably notice there is not that much differences, and that it's often really just micro-optimisation ^^
What might be more interesting is to look at the differences between versions of PHP : you might seen that some operations have been optimized between PHP 5.1 and 5.2, for instance.
For more informations, you can also have a look at Understanding Opcodes
Have fun !
EDIT : adding another test :
With this code :
$attr_open = '<ATTR>';
$attr_close = '</ATTR>';
$eol = "\n";
$data = array('a', 'b', 'c', 'd');
while ($item = current($data))
{
echo $attr_open, $item, $attr_close, $eol;
next($data);
}
You get :
line # op fetch ext return operands
-------------------------------------------------------------------------------
19 0 EXT_STMT
1 ASSIGN !0, '%3CATTR%3E'
20 2 EXT_STMT
3 ASSIGN !1, '%3C%2FATTR%3E'
21 4 EXT_STMT
5 ASSIGN !2, '%0A'
23 6 EXT_STMT
7 INIT_ARRAY ~3 'a'
8 ADD_ARRAY_ELEMENT ~3 'b'
9 ADD_ARRAY_ELEMENT ~3 'c'
10 ADD_ARRAY_ELEMENT ~3 'd'
11 ASSIGN !3, ~3
24 12 EXT_STMT
13 EXT_FCALL_BEGIN
14 SEND_REF !3
15 DO_FCALL 1 'current'
16 EXT_FCALL_END
17 ASSIGN $6 !4, $5
18 JMPZ $6, ->30
26 19 EXT_STMT
20 ECHO !0
21 ECHO !4
22 ECHO !1
23 ECHO !2
27 24 EXT_STMT
25 EXT_FCALL_BEGIN
26 SEND_REF !3
27 DO_FCALL 1 'next'
28 EXT_FCALL_END
28 29 JMP ->13
43 30 RETURN 1
31* ZEND_HANDLE_EXCEPTION
And, with this one (concatenations instead of ',') :
$attr_open = '<ATTR>';
$attr_close = '</ATTR>';
$eol = "\n";
$data = array('a', 'b', 'c', 'd');
while ($item = current($data))
{
echo $attr_open . $item . $attr_close . $eol;
next($data);
}
you get :
line # op fetch ext return operands
-------------------------------------------------------------------------------
19 0 EXT_STMT
1 ASSIGN !0, '%3CATTR%3E'
20 2 EXT_STMT
3 ASSIGN !1, '%3C%2FATTR%3E'
21 4 EXT_STMT
5 ASSIGN !2, '%0A'
23 6 EXT_STMT
7 INIT_ARRAY ~3 'a'
8 ADD_ARRAY_ELEMENT ~3 'b'
9 ADD_ARRAY_ELEMENT ~3 'c'
10 ADD_ARRAY_ELEMENT ~3 'd'
11 ASSIGN !3, ~3
24 12 EXT_STMT
13 EXT_FCALL_BEGIN
14 SEND_REF !3
15 DO_FCALL 1 'current'
16 EXT_FCALL_END
17 ASSIGN $6 !4, $5
18 JMPZ $6, ->30
26 19 EXT_STMT
20 CONCAT ~7 !0, !4
21 CONCAT ~8 ~7, !1
22 CONCAT ~9 ~8, !2
23 ECHO ~9
27 24 EXT_STMT
25 EXT_FCALL_BEGIN
26 SEND_REF !3
27 DO_FCALL 1 'next'
28 EXT_FCALL_END
28 29 JMP ->13
43 30 RETURN 1
31* ZEND_HANDLE_EXCEPTION
So, never much of a difference ^^
Here is an interesting one, my initial tests show that storing the newline char into a variable instead of PHP parsing it with each iteration is faster. See below:
$nl = "\n";
while ($item = current($data))
{
echo '<ATTR>',$item, '</ATTR>',$nl;
next($data);
}
There seems to be no measurable difference in using the string literals inside the loop vs. moving them to variables outside the loop. I threw together the following simple script to test this:
$length = 100000;
$data = array();
$totals = array();
for ($i = 0; $i < $length; $i++) {
$data[] = rand(1,1000);
}
$start = xdebug\_time\_index();
while ($item = current($data))
{
echo '<ATTR>',$item,'</ATTR>',PHP_EOL;
next($data);
}
$end = xdebug\_time\_index();
$total = $end - $start;
$totals["Warmup:"] = $total;
reset($data);
$start = xdebug\_time\_index();
while ($item = current($data))
{
echo '<ATTR>',$item,'</ATTR>',PHP_EOL;
next($data);
}
$end = xdebug\_time\_index();
$total = $end - $start;
$totals["First:"] = $total;
reset($data);
$startTag = '<ATTR>';
$endTag = '</ATTR>';
$start = xdebug\_time\_index();
while ($item = current($data))
{
echo $startTag,$item,$endTag,PHP_EOL;
next($data);
}
$end = xdebug\_time\_index();
$total = $end - $start;
$totals["Second:"] = $total;
foreach ($totals as $label => $data) {
echo $label,' ', $data,PHP_EOL;
}
I ran this several times and saw no discernable difference between the differing methods. In fact, sometimes the warmup was the fastest of the three.
When trying to microoptimize things such as this you really end up measuring the performance of the machine you are on more often than the actual code. Of note, you may want to use PHP_EOL instead of \n or defining a variable containing such.
Actually this is probably the fastest implementation. You could try to concat all in to one string but all of the concat operations are pretty expensive.
Everything has a cost. The goal is to minimize that cost as much as possible.
If you were thinking about concatenation check this resource for information on its performance. It's probably best to leave the code as-is.
If you really want to speed this up, use this instead:
ob_start();
while ($item = current($data))
{
echo '<ATTR>',$item, '</ATTR>', "\n";
next($data);
}
Output buffering flushes content more efficiently to the client, which speeds up your code much more than any micro-optimization can.
As an aside, in my experience micro-optimization is a useless endeavour when it comes to PHP code. I've never seen a performance problem get solved by clever use of a particular concatenation or variable declaration method. Real solutions tend to involve change to design or architecture or the use of less complicated algorithms.

Categories