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'm ranking a list based on a set of tie-breaking criteria using usort in PHP. My problem is that the tiebreakers aren't applied correctly when there are 3 or more ties to break. The function only sorts between 2 entries as it iterates through the array.
When 2 entries have identical Overall wins, the function checks Division wins; if those are identical, it checks Head to head; then Points if the tie still is not broken. This works great to break the tie between 2 entries, but with 3 or more ties, the iterative nature of this process is an issue.
Example:
3 entries have identical Overall wins and Division wins, so we check Head to head results.
Team 1 beat Team 2.
Team 2 beat Team 3.
Team 3 beat Team 1.
Therefore, we should move on to Points because the tie cannot be broken with Head to head as each team has one win over the other two teams. But my function doesn't ever make that third check, I guess because Team A and Team C aren't next to each other when usort() does it's thing...I'm not sure.
Here is the comparison function I pass into usort:
function set_division_order($a, $b) {
if ($a['wins'] == $b['wins'] && $a['losses'] == $b['losses']) { //same overall record
if ($a['div_wins'] == $b['div_wins'] && $a['div_losses'] == $b['div_losses']) { //same division record
$h2h = get_h2h_result($year, $a['team_id'], $b['team_id']);
if ($h2h == 0) { //same head-to-head record
return ($b['pts'] - $a['pts']);
}
else { //head-to-head winner
return $h2h;
}
}
else { //different division record
return ($b['div_wins'] - $a['div_wins']);
}
}
else { //different overall record
return ($b['wins'] - $a['wins']);
}
}
The array getting passed into usort($array, 'set_division_order') which is causing problems:
Array
(
[0] => Array
(
[team_id] => 1
[wins] => 3
[losses] => 2
[ties] => 0
[div_wins] => 3
[div_losses] => 2
[div_ties] => 0
[pts] => 513.9
)
[1] => Array
(
[team_id] => 2
[wins] => 3
[losses] => 2
[ties] => 0
[div_wins] => 3
[div_losses] => 2
[div_ties] => 0
[pts] => 504.1
)
[2] => Array
(
[team_id] => 3
[wins] => 3
[losses] => 2
[ties] => 0
[div_wins] => 3
[div_losses] => 2
[div_ties] => 0
[pts] => 517.7
)
[3] => Array
(
[team_id] => 4
[wins] => 4
[losses] => 1
[ties] => 0
[div_wins] => 4
[div_losses] => 1
[div_ties] => 0
[pts] => 491.9
)
[4] => Array
(
[team_id] => 5
[wins] => 2
[losses] => 3
[ties] => 0
[div_wins] => 2
[div_losses] => 3
[div_ties] => 0
[pts] => 393.3
)
[5] => Array
(
[team_id] => 6
[wins] => 0
[losses] => 5
[ties] => 0
[div_wins] => 0
[div_losses] => 5
[div_ties] => 0
[pts] => 377.9
)
)
Sorry this was kind of long, but hopefully the problem is pretty evident. Now it's just time for a solution! I've scoured the PHP resources for the various sort functions, with no luck. I can't be the only one trying to break a 3-way tie with PHP. :)
If I can get just the tied teams matching that criteria into a separate array, I could use a function to re-sort the original sorted array against the values of this new sub-array to order the tied teams within the main array.
...And my head just exploded.
Thanks!
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
I am trying to build a website that will display the text in multiple languages.
I have a table 'text' with all the languages. If the text does not exist in the chosen language it has to display the default language.
query SELECT * FROM text WHERE TextId = 10
results in
Id TextId LanguageId Text
10 10 1 first name
13 10 2 名前
If I r_print this result I get something like this
Array ( [0] => Array ( [0] => 10 [Id] => 10 [1] => 10 [TextId] => 10 [2] => 1 [LanguageId] => 1 [3] => first name [Text] => first name )
[1] => Array ( [0] => 13 [Id] => 13 [1] => 10 [TextId] => 10 [2] => 2 [LanguageId] => 2 [3] => 名前 [Text] => 名前 ) )
How can I check that LanguageId 2 exist in this array ?
the problem is that it is possible that TextId 2 and Id 2 can also exist in this array.
Is this possible to do with in_array()?
Here is a function that can check if LanguageId equals a special value .
function isLanguageIdExists($yourArray , $LanguageId){
$exists=false;
foreach($yourArray as $array){
if(isset($array['LanguageId'])&& $array['LanguageId'] == $LanguageId){
$exists=true;break;
}
}
return $exists;
}
$exist = isLanguageIdExists($yourArray , 2);//return true or false
You can check by isset the key and match the value in php.
$dataArray = array(
0 => array(0 => 10 ,'Id' => 10, 1 => 10, 'TextId' => 10, 2 => 1, 'LanguageId' => 1),1 => array(0 => 10 ,'Id' => 10, 1 => 10, 'TextId' => 10, 2 => 1, 'LanguageId' => 1)
);
foreach($dataArray as $value) {
if(isset($value['LanguageId']) && $value['LanguageId'] == 2) {
echo 'language ID 2 is available';
}
}
Working Demo
After giving this some more thought I came up with a maybe not so elegant solution.
Instead of getting an array back I modified the SQL Query to give one row back with the default language (English) and a user selected language (Japanese).
It uses two left joins. This shows that I received (some) training in SQL but am really not at ease with multidimensional arrays.
Query
def_text = text in default language
usr_text = text in user chosen language
$table01 = "text";
$query="SELECT $table01.TextId,
text_def.Text as def_text,
text_usr.Text as usr_text
FROM $table01
LEFT JOIN $table01 as text_def ON $table01.TextId = text_def.TextId AND text_def.LanguageId = $_SESSION[default_language]
LEFT JOIN $table01 as text_usr ON $table01.TextId = text_usr.TextId AND text_usr.LanguageId = $_SESSION[language]
WHERE $table01.TextId=$mess;";
after getting back the results it is easy to check with isset() or empty() to see if the text is available in the user selected language
I have the following output of an array using PHP. I need to do two things... First, I need to sort the array so it prints by the most recent date. I can't use a simple sort, because the date is outputted in the format mm/dd/yyyy (and not a regular time stamp) ...
Then I need to count how many rows exist for each year.
So, in the example below, I would need to know that there are ...
2 entries from 2010
2 entries from 2011
1 entry from 2012
Stop counting when there are no more rows
Since the year is not separate from the rest of the date digits, this also complicates things...
Array
(
[0] => Array
(
[racer_date] => 11/15/2010
[racer_race] => Test Row 4
[racer_event] => 321
[racer_time] => 16
[racer_place] => 12
[racer_medal] => 1
)
[1] => Array
(
[racer_date] => 7/15/2010
[racer_race] => Test Row 3
[racer_event] => 123
[racer_time] => 14
[racer_place] => 6
[racer_medal] => 0
)
[2] => Array
(
[racer_date] => 7/28/2011
[racer_race] => Test Row
[racer_event] => 123
[racer_time] => 10
[racer_place] => 2
[racer_medal] => 2
)
[3] => Array
(
[racer_date] => 10/9/2011
[racer_race] => Test Row 2
[racer_event] => 321
[racer_time] => 12
[racer_place] => 3
[racer_medal] => 3
)
[4] => Array
(
[racer_date] => 10/3/2012
[racer_race] => World Indoor Championships (final)
[racer_event] => 400m
[racer_time] => 50.79
[racer_place] => 1
[racer_medal] => 1
)
)
function cmp($a, $b)
{
if (strtotime($a["racer_date"]) == strtotime($b["racer_date"])) {
return 0;
}
return (strtotime($a["racer_date"]) < strtotime($b["racer_date"])) ? -1 : 1;
}
usort($array, "cmp");
call your array $array, and above code will sort it..
And to count entities you'll need to run foreach and check date('Y',strtotime($a["racer_date"])) in that foreach which will give you year in 4 digit..