so I have an array that looks like this (easier to see then the raw output)
0 | from:2 page | to:1 split
1 | from:1 split | to:3 page
2 | from:1 split | to:4 page
3 | from:1 split | to:5 page
4 | from:3 page | to:0 join
5 | from:4 page | to:0 join
6 | from:5 page | to:0 join
7 | from:8 page | to:0 join
8 | from:0 join | to:12 page
9 | from:1 split | to:8 page
10 | from:12 page | to:10 end
11 | from: start | to:2 page
what I would like to do is to somehow parse through it and come up with the following:
0 | start
1 | page
2 | split 3, 4, 5, 8
3 | page
4 | end
so essentially I'm trying to organize this into a final array that follows the path from start to finish.
Rules of engagement:
Where there is a split: combine the "to page" into a sub array, and where there is a "to join", remove the reference. and where there is a "from join to page" just make the page. so final output should look something like this:
array(
'start',
'page',
'split' => array (
3, 4, 5, 8
),
'page',
'end'
)
UPDATE:
here is the raw format I'm working with
Array
(
[operators] => Array
(
[0] => Array
(
[type] => join
)
[1] => Array
(
[type] => split
)
[2] => Array
(
[type] => page
)
[3] => Array
(
[type] => page
)
[4] => Array
(
[type] => page
)
[5] => Array
(
[type] => page
)
[8] => Array
(
[type] => page
)
[9] => Array
(
[type] => start
)
[10] => Array
(
[type] => end
)
[12] => Array
(
[type] => page
)
)
[links] => Array
(
[0] => Array
(
[fromOperator] => 2
[toOperator] => 1
)
[1] => Array
(
[fromOperator] => 1
[toOperator] => 3
)
[2] => Array
(
[fromOperator] => 1
[toOperator] => 4
)
[3] => Array
(
[fromOperator] => 1
[toOperator] => 5
)
[4] => Array
(
[fromOperator] => 3
[toOperator] => 0
)
[5] => Array
(
[fromOperator] => 4
[toOperator] => 0
)
[6] => Array
(
[fromOperator] => 5
[toOperator] => 0
)
[7] => Array
(
[fromOperator] => 8
[toOperator] => 0
)
[8] => Array
(
[fromOperator] => 0
[toOperator] => 12
)
[9] => Array
(
[fromOperator] => 1
[toOperator] => 8
)
[10] => Array
(
[fromOperator] => 12
[toOperator] => 10
)
[11] => Array
(
[fromOperator] => 9
[toOperator] => 2
)
)
)
``
Boo Yahh!!
I had to nap on it, but now I got that 4 sure.
<?php
$array = array (
'operators' =>
array (
0 =>
array (
'type' => 'join'
),
1 =>
array (
'type' => 'split'
),
2 =>
array (
'type' => 'page'
),
3 =>
array (
'type' => 'page'
),
4 =>
array (
'type' => 'page'
),
5 =>
array (
'type' => 'page'
),
8 =>
array (
'type' => 'page'
),
9 =>
array (
'type' => 'start'
),
10 =>
array (
'type' => 'end'
),
12 =>
array (
'type' => 'page'
),
),
'links' =>
array (
0 =>
array (
'fromOperator' => 2,
'toOperator' => 1
),
1 =>
array (
'fromOperator' => 1,
'toOperator' => 3
),
2 =>
array (
'fromOperator' => 1,
'toOperator' => 4
),
3 =>
array (
'fromOperator' => 1,
'toOperator' => 5
),
4 =>
array (
'fromOperator' => 3,
'toOperator' => 0
),
5 =>
array (
'fromOperator' => 4,
'toOperator' => 0
),
6 =>
array (
'fromOperator' => 5,
'toOperator' => 0
),
7 =>
array (
'fromOperator' => 8,
'toOperator' => 0
),
8 =>
array (
'fromOperator' => 0,
'toOperator' => 12
),
9 =>
array (
'fromOperator' => 1,
'toOperator' => 8
),
10 =>
array (
'fromOperator' => 12,
'toOperator' => 10
),
11 =>
array (
'fromOperator' => 9,
'toOperator' => 2
)
)
);
Code:
//Flatten to simplify [$op_id => $array['operators'][n]['type']]
//array_combine and array_keys, just makes sure the keys match
//the original array, because we are missing a few keys (7,8 and 11)
//we have to do this or we lose those references.
$arr_op = array_combine(array_keys($array['operators']), array_column($array['operators'], 'type'));
//print_r($arr_op);
//get our instruction list - combine data to simplify.
//this saves us a bit of work doing the lookup and managing multiple arrays
$instructions = [];
foreach($array['links'] as $link){
$instructions[] = [
'fromOperator' => $link['fromOperator'],
'fromOp' => $arr_op[$link['fromOperator']], // we need them keys to match here
'toOperator' => $link['toOperator'],
'toOp' => $arr_op[$link['toOperator']] //and here
];
}
//print_r($instructions);
$opp_id = array_search('start',$arr_op); //9 start
//print_r($opp_id);
$i=0;
$output = [];
//loop as long as we have some instructions to process
while(count($instructions)){
//get the current key of the array
$key = key($instructions);
//is this our instruction?
//we are forced to {potentially} loop the whole array to find it
//we cannot use array search (even after flattening it out) because of the duplicates
if($instructions[$key]['fromOperator'] == $opp_id){
//get and remove the instruction - array reduction
$instruction = array_splice($instructions, $key, 1)[0];
//print_r($instruction);
//print_r($instructions);
//just for sanity checks.
echo "{$i} | from:{$instruction['fromOp']} {$instruction['toOperator']} | to:{$instruction['fromOperator']} {$instruction['toOp']}\n";
//if the last operation is end, use it as there is no fromOp = end
$opperation = 'end' == $instruction['toOp'] ? 'end' : $instruction['fromOp'];
//process instruction
switch($opperation){
case 'join':
//skip
break;
case 'split':
//split has to be done as a group
$output['split']=array_column(array_filter($array['links'],function($ins)use($opp_id){return $ins['fromOperator']==$opp_id;}),'toOperator');
break;
default: //start, page, end
$output[] = $opperation;
//when we find the end, break the switch, break the while
if($opperation == 'end') break 2;
break;
}//end switch
//get the operation key for the next instruction as we consumed it, Yum!
$opp_id = $instruction['toOperator'];
++$i;
}//end if
//move the array pointer forward, or reset on false (start over when we hit the end of the array)
if(false === next($instructions)) reset($instructions);
}//end while
echo "\n";
print_r($output);
Output
0 | from:start 2 | to:9 page
1 | from:page 1 | to:2 split
2 | from:split 4 | to:1 page
//Some "magic" happens here and we warp to 0
3 | from:page 0 | to:4 join
4 | from:join 12 | to:0 page
5 | from:page 10 | to:12 end
Array
(
[0] => start
[1] => page
[split] => Array
(
[0] => 3
[1] => 4
[2] => 5
[3] => 8
)
[2] => page
[3] => end
)
Sandbox
Limitations
Because PHP array keys are unique, your forced to group all the "split" operations into one lump. With your current input array structure there is no "real" way around it, even without "using split as a key". (hopefully this illiterates the issues)
//The #{n} in the first column, is the (apx) order this thing runs in.
//#(hashtag) will be used for all numbers with a # (in my explanation below)
//if they don't have a # and are code, assume they are the second column value (in my explanation below)
#2 - 0 | from:2 page | to:1 split //--> start of split
#3 - 1 | from:1 split | to:3 page //--> go to 3
#dup - 2 | from:1 split | to:4 page // -> go to 4
#4 - 3 | from:1 split | to:5 page // -> go to 5
#dup - 4 | from:3 page | to:0 join //<-- if you go to 0 -> 12 -> end
#5 - 5 | from:4 page | to:0 join //<-- if you go to 0 -> 12 -> end
#dup - 6 | from:5 page | to:0 join //<-- if you go to 0 -> 12 -> end
#6 - 7 | from:8 page | to:0 join
#7 - 8 | from:0 join | to:12 page
#dup - 9 | from:1 split | to:8 page //--> go to 8 end of split
#8 - 10 | from:12 page | to:10 end // {exit}
#1 - 11 | from: start | to:2 page
As you can see above, the #dup ones all come from opp:1 or $array['operators'] = [1 =>['type' => 'split']], but there is only 1 to:1 at #2 and 4 from:1 items. So we are forced to split the execution of these because you cant go to 4 items at the same time for 1 item. We can do this with a loop, or with this big huge mess I did there.
For example take #3 our last good path:
#3 - 1 | from:1 split | to:3 page //--> go to 3
~4 - 4 | from:3 page | to:0 join //<-- if you go to 0 -> 12 -> end
~5 - 8 | from:0 join | to:12 page // way out of wack now.
~6 - 10 | from:12 page | to:10 end {premature termination}
As you see we cannot follow those paths, so we are forced to process these as a group. If we did that (follow the path) we would have only processed #1, #2, #3, ~4, ~5 and ~6 and then the program ends. This is what happened in my previous answer (basically) and how I knew it wasn't correct. Also due to the duplicated 0 we can't process any of those or well wind up at the end shortly. I don't see any {other} way to solve that given the structure of the data.
How I did it (briefly)
The "trick" here was manually mapping out how it runs, above.
Using that knowledge I built an instruction list (to reduce complexity), so we are dealing with one array without the lookups for the operation names, I called that list $instructions (creative I know).
Next if($instructions[$key]['fromOperator'] == $opp_id)
TRUE: we just eat that $instruction = array_splice($instructions, $key, 1)[0]; which removes and returns a portion of the array. So our list of instructions is constantly being reduced as we are able to process them.
FALSE: we continue to the next instruction and reset the array if the array pointer is at the end. if(false === next($instructions)) reset($instructions); and start back at 1 (in this list) on the next instruction.
Because there is no "real" way to order this, we may have to loop over the array several time, this is easier to do by removing each instruction as we process it.
Then it's pretty trivial to do a switch and collect our output, with a bit of "finagling" with the "split stuff" and the end operation.
the "finagling" is just pulling an array of all the toOperator from the main array where the fromOperator has the same int as the split has for it's key (or 1 in this case)
Lastly we either run out of array items, or we hit this if($opperation == 'end') break 2; which breaks out of both the switch and the while loop. Who knew you could do that with break {this guy}...
I left a bunch of comments in there, hopeful this explains how I did it and what the main issue was.
Improvements
Where I have this monstrosity, which just gets a flat array of all the toOperator values for all items that are "Splits" (all dynamic like). I can come up with at least 5 ways to do this, this was just the way I picked.
$output['split']=array_column(array_filter($instructions,function($ins)use($opp_id){return $ins['fromOperator']==$opp_id;}),'toOperator');
You could iterate over each "split" and recursively call the switch "somehow". Because I am removing each instruction, the first "Split" gets pulled out of the instruction list before we can check if it's a split. This makes it a bit difficult to work with. However you can do this (if you need to fix that):
$instructions = array_splice($instructions, $key, 0, [instructions]);
Which should put it back in the instruction list. The magic of array_splice even if that is a bit counter productive. Then you just need to loop over them, and if they don't have a goto 0 you could follow that path where it leads. Which may solve some issues with ordering, that may or may not happen. One other issue here is you will get multiple page values in the output, as I just skip over them (pun intended). So keep that in mind if you try to iterate over it. The way I did it wasn't necessary to deal with that. But the basic idea is to functionality (make part or all of it a function and then) call it multiple times for the splits as they happen.
One other issue, that I didn't bother fixing, is that not all the split items are are actually removed from the instruction list. In this example this doesn't matter because we have the end tag. However it would be pretty easy to clean that up when doing the above improvements.
In any case I will leave that as an exercise for the reader.
Final words
PS: if you numbered it like above, it would have saved me a TON of time. It was a fun challenge though.
Hope it helps, this is about the best you can get with the data you provided due to the above issues. There may be some minor performance things to be gained etc, but that pretty much covers it.
Cheers!!
*PPS: yes I know my spelling and grammar suck. Oh the joys of dyslexia. I supose one cannot be good at everything.... It takes me about a billion edits to get it somewhat readable.
I have a grid of img squares that can be dragged into any order using the sortable library. Each img is a visual representation of a result from a mySQL db query that selects any image that shares an 'imageparent' identifier. The order they're presented in the grid is taken from the 'imageorder' column in the database and starts at 0 and works in sequence up to the nth number of images returned.
The purpose of dragging the img grid is to be able to change the 'imageorder' index. On completion of the drag, the sortable library POSTS an 'imageorder' var by ajax to service.php and is received correctly. So rather than the original 0,1,2,3,4,5,6,7 order of the original, it sends a string like 2,1,0,3,4,5,7,6. Not too hard to grasp. After I switch the order the orderList var sent to service.php is always correct, but the array I end up sending to the db and setting as my session var becomes a little garbled in order after the second or third drag and I'm not quite sure why.
Code Examples and Comments
$_SESSION['selectedCsImages'] Array structure:
[0] => Array
(
[imagename] => "Title"
[imageorder] => 0
[imageid] => 43
)
[1] => Array
(
[imagename] => "Title"
[imageorder] => 1
[imageid] => 21
)
[2] => Array
(
[imagename] => "Title"
[imageorder] => 2
[imageid] => 3
)
etc...
Services.php extract:
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
// Turn the orderList posted into an array
$removeChars = array('"','[',']');
$orderList = str_replace($removeChars, "", $_POST['order']); // POST received fine.
$listArray = explode(",",$orderList);
// Retrieve the session array
$sorting = $_SESSION['selectedCsImages'];
/* My logic is that I compare the $sorting array to $listArray and reorder $sorting by 'imageorder' to match $listarray */
usort($sorting, function($a, $b) use ($listArray) {
return array_search($a['imageorder'], $listArray) - array_search($b['imageorder'], $listArray);
});
/* I now have a $sorting array that (sometimes, hence the problem) matches the order that the images had just been dragged into by the user. Typically, as I mentioned above, it's correct after the first drag, but not always after the second or third where it creates a new order that I can't see a pattern or logic in. */
/* Had there not been errors with the usort function, I (would) have a $sorting array in the order I want but with imageorder values referring to pre-sorting. I iterate through the array and set each key to 0, 1, 2, etc. so that I have an array in the correct order and with each imageorder correctly stating its place.*/
$i = 0;
foreach ($sorting as $key => $value) {
$sorting[$key]['imageorder'] = $i;
$i++;
}
/* The information is attempted to be sent to the db and, on success I update the session var */
// Database code (runs succesfully and updates the db as per the image orders found in the $sorting array)
$_SESSION['selectedCsImages'] = $sorting;
Debugging:
From debugging, it appears that something happens with the usort function when I call this page from ajax for the second or third time. Everything after this follows through fine and processes the correct or incorrect order as per expectations. The orderList var posted by sortable is correct each time. I'd provide a sample of the $sorted var after usort each time but it's as simple to describe it as the above array example in an order I didn't specify after dragging and I can't see a pattern in the seemingly random order it outputs.
From researching, I had thought that it was an issue with session vars being retained until the page is refreshed but it appears that the ajax call to services.php should refresh the $_SESSION['selectedCsImages'] var. I had also read that, perhaps, I was unknowingly using referenced array values and - as I source from a session var to a new array and, ultimately, save back to this session var from this array - I may have created some messy referencing feedback. However, I tried using $sorted = (array)clone(object)$_SESSION['selectedCsImages']; before attempting usort and the results didn't change.
PHP error logs are showing nothing.
Updates:
Per the suggestion of #Ayaou, I've checked the output of $listArray and am getting some unexpected results. I'd wrongly assumed that as the posted $orderList was correct, that the exploded array would not be a culprit.
Here's the output of print_r($listArray) after completing the following order swaps of 16 img elements: 1st with 2nd, 2nd last with last,6th with 7th:
1st and 2nd:
(
[0] => 1
[1] => 0
[2] => 2
[3] => 3
[4] => 4
[5] => 5
[6] => 6
[7] => 7
[8] => 8
[9] => 9
[10] => 10
[11] => 11
[12] => 12
[13] => 13
[14] => 14
[15] => 15
)
last and 2nd last:
(
[0] => 1
[1] => 0
[2] => 2
[3] => 3
[4] => 4
[5] => 5
[6] => 6
[7] => 7
[8] => 8
[9] => 9
[10] => 10
[11] => 11
[12] => 12
[13] => 13
[14] => 15
[15] => 14
)
6th with 7th:
(
[0] => 1
[1] => 0
[2] => 2
[3] => 3
[4] => 4
[5] => 6
[6] => 5
[7] => 7
[8] => 8
[9] => 9
[10] => 10
[11] => 11
[12] => 12
[13] => 13
[14] => 15
[15] => 14
)
I was progressing with the idea that $listArray would show a sequential 0,1,2,3,etc. each time with only the two swapped items showing order changes. As it's not, I'll look back again at $orderList and check if my sortable library is updating the orders it's obtaining correctly from the updated session var. Older order swaps are being retained somewhere along the chain where they shouldn't.
The solution is on your sortable form (on the front end), so instead of sending the imageorder on your 'order' post data, send the imageid index.
Then change your sort callback like this
//Use imageid index instead of imageorder
usort($sorting, function($a, $b) use ($listArray) {
return array_search($a['imageid'], $listArray) - array_search($b['imageid'], $listArray);
});
I have tried many ways to do this but no luck. I'm trying to take value from First array and generate second array and put the second array in the first array.
The code that I have now, generate the first array, in this array I have column called prereq_id I need to take this value and match it with courses table to bring its information in the courses table course_id=prereq_id. Any help would be highly appreciated
The array output is like this right now
[course_id] => 2
[curriculum_id] => 1
[set_number] => 0
[course_code] => GCIS 516
[course_name] => Data-Centric Concepts and Methods
[credits] => 3
[semester_ava] => 2
[prereq_id] => 10
[set] => 3
php
$result2 = $mysqli->query("SELECT *
FROM curriculumcourses
INNER JOIN courses ON curriculumcourses.course_id = courses.course_id
LEFT JOIN prerequisites ON courses.course_id=prerequisites.course_id
WHERE curriculum_id='$ids' ");
?>
<?php
for ($x = 1; $x <= $mysqli->affected_rows; $x++) {
$rows[] = $result2->fetch_assoc();
}
echo "<pre>";
print_r($rows);
echo "</pre>";
The result I need look like this
[course_id] => 2
[curriculum_id] => 1
[set_number] => 0
[course_code] => GCIS 516
[course_name] => Data-Centric Concepts and Methods
[credits] => 3
[semester_ava] => 2
[prereq_id] => 10
[set] => 3
[course_code] => GCIS 508
[course_name] =>Database Management Systems
[credits] => 3
[semester_ava] => 1
when i print_r my array gives
Array (
[0] => Array ( [userid] => 2 [popularity] => 41.7 )
[1] => Array ( [userid] => 5 [popularity] => 33.3 )
[2] => Array ( [userid] => 7 [popularity] => 25.0 )
)
is the array returned after querying users and sort by popularity desc, meaning
user with id 2 has popularity 41.7, user with id 5 has popularity 33.3 and so on,
Then i have a dynamic query that shows each user with his popularity
example: user with id 2 has popularity of 41.7
user with id 5 has popularity of 33.3 etc.
All i want is to show the position(outer array index) of each user if user id of dynamic query matches the output of array above then increment by 1 because array index always starts 0
example: user with id 2, will have position of 1 (the winner)
user with id 5, will have position of 2
user with id 7, will have position of 3 etc..
how can i do that...
This code modifies array and ads new key 'position' (= $key + 1) to each element.
function addPosition(&$item, $key) {
$item['position'] = $key + 1;
}
array_walk($data, 'addPosition');
I have a multidimensional array like this:
Array (
[0] => Array ( [ans_id] => 1 [ans_name] => PHP Hypertext Preprocessor [ques_id] => 1 [right_ans] => Yes [ques_name] => What is the acronym of PHP? [section_id] => 1 [section_name] => PHP )
[1] => Array ( [ans_id] => 2 [ans_name] => Preety Home Page [ques_id] => 1 [right_ans] => No [ques_name] => What is the acronym of PHP? [section_id] => 1 [section_name] => PHP )
[2] => Array ( [ans_id] => 3 [ans_name] => Programmed Hypertext Page [ques_id] => 1 [right_ans] => No [ques_name] => What is the acronym of PHP? [section_id] => 1 [section_name] => PHP )
[3] => Array ( [ans_id] => 4 [ans_name] => Programmed Hypertext Preprocessor [ques_id] => 1 [right_ans] => No [ques_name] => What is the acronym of PHP? [section_id] => 1 [section_name] => PHP ) )
My table is like this:
ans_id ans_name ques_id right_ans
1 PHP Hypertext Preprocessor 1 Yes
2 Preety Home Page 1 No
3 Programmed Hypertext Page 1 No
4 Programmed Hypertext Preprocessor 1 No
5 Andy Suraski 12 No
6 Zeev Gutman 12 No
7 Rasmus Lerdorf 12 Yes
8 Perl 12 No
I want to retrieve the answers in sets of common question id's
i.e. one set of all answers for Ques_id='1', 2nd set of all answers for ques_id='12', etc.
I am supposed to use this code:
foreach($all_ans_cat as $r)
{
echo $r['ans_id']." ".$r['ans_name']."<br>";
}
This is retrieving all the values present in the table as one set and again in the 2nd set the same values are being displayed.
Select all answers sorted by ques_id and generate array with structure needed
$questions = array();
$prevQuestionId = null;
foreach ($all_ans_cat as $r) {
if ($r['ques_id'] !== $prevQuestionId) {
$questions[] = array();
}
$questions[sizeof($questions)-1][] = $r;
$prevQuestionId = $r['ques_id'];
}
Result array would be:
0:
- [ans1, ques1]
- [ans2, ques1]
...
1:
- [ans5, ques13]
- [ans6, ques13]
...
...
you can use a query with group by and aggregate function
have a look at
http://www.w3schools.com/sql/sql_groupby.asp