Hi I have a PHP array like this
$table=array();
$subject_names=array();
$subject_names[118]="English";
$subject_names[108]="Software Engeneering";
$table['Josh'][118]['int'] =55;
$table['Josh'][118]['ext'] = 10;
$table['Josh'][108]['int'] =45;
$table['Josh'][108]['ext'] = 12;
$table['Matt'][118]['int'] =45;
$table['Matt'][118]['ext'] = 12;
$table['Matt'][108]['int'] =50;
$table['Matt'][108]['ext'] = 15;
Here 118 and 108 are subject_id I am trying to format it like this
student | English | Software Engeneering |
| int. mark | ext. mark | int. mark | ext. mark |
___________________________________________________________
Josh | 55 | 10 | 45 | 12
Matt | 45 | 12 | 50 | 15
I tried
echo "Student Name\t";
foreach($subject_names as $sub_name)
{
echo "$sub_name\t";
}
echo "<br>";
foreach($table as $sname => $subjects){
echo "$sname\t";
foreach($subjects as $subject_name => $types)
{
foreach($types as $marks)
{
echo "$marks\t";
}
}
echo "<br>";
}
It working fine but if I change the position of array item of table like
$table['Josh'][118]['int'] =55;
$table['Josh'][108]['int'] =45;
$table['Josh'][118]['ext'] = 10;
$table['Josh'][108]['ext'] = 12;
It won't give a correct result. Is there anyway to assure that the result are always correct.
Thank you for your any help and suggestions
Here's a solution I wrote for your request, picking the scores using the $subject_names as control rather than the students' scoresheet (I hope you get what I mean after going through the codes)...
$table=array();
$subject_names=array();
// notice that I switched subject order, just to show that subjects control the marks displayed thereby ensuring consistent score mapping
$subject_names[108]="Software Engeneering";
$subject_names[118]="English";
// and I'm using the rearranged scores (the sample use-case you specified in the question that distorts your output)
$table['Josh'][118]['int'] =55;
$table['Josh'][108]['int'] =45;
$table['Josh'][118]['ext'] = 10;
$table['Josh'][108]['ext'] = 12;
$table['Matt'][118]['int'] =45;
$table['Matt'][118]['ext'] = 12;
$table['Matt'][108]['int'] =50;
$table['Matt'][108]['ext'] = 15;
echo "Student Name\t";
foreach($subject_names as $sub_name)
{
echo "$sub_name\t";
}
echo "\n";
// proposed solution:
foreach($table as $sname => $subjects){
echo "$sname\t";
foreach ($subject_names as $subject_id => $name) {
foreach ($subjects[$subject_id] as $mark) {
echo "$mark\t";
}
}
echo "\n";
}
Here's the output of the script above...
Student Name Software Engeneering English
Josh 45 12 55 10
Matt 50 15 45 12
Running the same data through the script provided in the question, here's the output (distorted)...
Student Name Software Engeneering English
Josh 55 10 45 12
Matt 45 12 50 15
P.S: 'Engeneering' should be 'Engineering'
I hope I've been helpful.
Cheers!
I've created a for loop to count 1-30 and want to match mysql number columns 1 - 30 with its attach string data column name and display string inside for loop.
Mysql structure:
|-------------|-------------|--------------|
| id | Number | Name |
|-------------|-------------|--------------|
| 90 | 3 | Test Data |
|-------------|-------------|--------------|
tried simular attempts such as:
foreach($db->results() as $result) {
$count = $result->Number;
$results = $result->Name;
}
for($i=1;$i<=30;$i++) {
if($count == $i) {
echo $results;
}else{
echo '';
}
}
Needing help! Thank you!!!
================================================================================================================================================================
Ok here is what I am trying to accomplish... It works with assigning to the correct number when matching (Thanks for the suggestion). Here is what I have:
$name = array();
$number = array();
foreach($forDB->results() as $for){
$name = $for->firstname;
$number = $for->number;
for($i=1;$i<=30;$i++) {
if($i<=5){
if($number == $i) {
echo $i.' = '.$name;
}
} //then the rest of remanding numbers to 30
}
}
this echos:
2 = name1
4 = name4
But what I would like to do is also echo the numbers of $i between the numbers and values as:
1
2 = name1
3
4 = name4
5
So I try this but it appends to each value:
$name = array();
$number = array();
foreach($forDB->results() as $for){
$name = $for->firstname;
$number = $for->number;
for($i=1;$i<=30;$i++) {
if($i<=5){
if($number == $i) {
echo $i.' = '.$name.'<br><br>';
} else {
echo $i.'<br>';
}
} else {
echo $i;
}
}
}
Results:
2
3
4
5
6
7
1
2 = name2
3
4
5
6
7
1
2
3
4 = Jeff
1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4 5 6 7
I think you should initialize your count and name variables before the foreach loop as an array then in the foreach loop fill it up with the results, then iterate through it in the for loop.
I need help writing the logic of the php script which sorts data into a certain format...
Firstly the script needs to loop through each s1 value and ping an endpoint to get the ml values (more like) which are actually referencing other s1 records. this is the easy part! the data is returned like so;
Table 1
s1 | ml
----------
1 | -
2 | 3,4
3 | 2,8,9
4 | -
5 | 2
6 | 1
7 | 10
8 | -
9 | -
10 | -
Condition 1: As you can see the endpoint returns data for the s1 value telling it other s1 records are similar to other ones, but the direction of ml is not always bidirectional. sometimes, like when s1=6 the ml value is 1 however when s1=1 there isn't a ml value.
Condition 2: Again just to explain the ml records, look above and below where s1=5 (above) and where s1=2 + rec=5 (below), this script needs to realise there is already an s1 record for it's value and that it should be added there.
Condition 3: Note how when s1=2,ml=3 this is stored but when s1=3,ml=2 this is ignored because we have the reverse record.
I basically want to match all the data into 1 sorted 'profile' so it ends up in the below format which i will store in another db table of 'sorted' records.
Table 2
s1 | rec
----------
2 | 3
2 | 4
2 | 8
2 | 9
2 | 9
2 | 5
6 | 1
7 | 10
This has been racking my brains for days now, I need something thats efficient because in the end it will deal with millions of records and I'm sure there is an easy solution but i just can't figure how to start it.
I tried the following, but I'm stuck and don't know how to go further;
public function getrelated($id='', $t=''){
if($id != ""){
$get = Easytest::where('s1','=',$id)->get();
if(count($get) > 0){
$ret= array();
foreach($get as $go){
$v = explode(",", $go->s2);
foreach ($v as $e) {
if($e != $t){
$ret[$e] = $this->getrelated($e, $id);
}
}
}
if(count($ret) > 0){
return $ret;
}else{
return "";
}
}else{
return $id;
}
}else{
return "";
}
}
public function easytest(){
ob_start();
$a = array(
array("s1"=>1,"s2"=>implode(",",array()).""),
array("s1"=>2,"s2"=>implode(",",array(3,4)).","),
array("s1"=>3,"s2"=>implode(",",array(2,8,9)).","),
array("s1"=>4,"s2"=>implode(",",array()).""),
array("s1"=>5,"s2"=>implode(",",array(2)).","),
array("s1"=>6,"s2"=>implode(",",array(1)).","),
array("s1"=>7,"s2"=>implode(",",array(10)).","),
array("s1"=>8,"s2"=>implode(",",array()).""),
array("s1"=>9,"s2"=>implode(",",array()).""),
array("s1"=>10,"s2"=>implode(",",array()).""),
array("s1"=>11,"s2"=>implode(",",array(12)).","),
array("s1"=>12,"s2"=>implode(",",array(2)).",")
);
//return Easytest::insert($a);
$records = Easytest::all();
foreach ($records as $record) {
$id = $record->s1;
echo "ROW: ".$id." > ";
$record->s2 = ltrim($record->s2,",");
$ml = explode(",",$record->s2);
if(count($ml) >= 1){
foreach ($ml as $t) {
echo "RESULT: ".$t." -".print_r($this->getrelated($t, $id), true);
echo ",\n";
}
}
echo " <br><br>\n\n";
}
return ob_get_clean();
}
Ok, so I eventually solved this... esentially this is the code below;
improvements welcome :)
You need to call the function like so
related(array('searched'=>array(),'tosearch'=>array(13)));
function:
public function related($input){
$searched = $input['searched'];
$ar = array();
$bits = array();
if(count($input['tosearch']) != 0){
$get = Easytest::orWhere(function($query) use ($input)
{
foreach ($input['tosearch'] as $k=>$v) {
$query->orWhere('s2', 'LIKE', '%,'.$v.',%')->orWhere('s1', '=', $v);
}
})
->orderBy('s1', 'ASC')->get();
foreach ($input['tosearch'] as $k=>$v) {
unset($input['tosearch'][$k]);
$input['searched'][$v] = $v;
}
foreach ($get as $result) {
$thesebits = explode(",", trim($result->s2,","));
foreach ($thesebits as $smallbit) {
if($smallbit != ""){
$bits[] = $smallbit;
}
}
$bits[] = $result->s1;
$bits = array_unique($bits);
foreach ($bits as $k=>$v) {
if(($key = array_search($v, $input['searched'])) == false) {
$input['tosearch'][$v] = $v;
}else{
unset($input['tosearch'][$v]);
}
}
$input['tosearch'] = array_unique($input['tosearch']);
}
return $this->related($input);
}else{
return $input;
}
}
This is a follow-up question for my earlier question here:
Some help "syncing" two loops in PHP
I want to take a list of dates and show them as ranges if their date is the same or max 1 day apart.
This is the output of my database:
+-----+------------+
| uid | date |
+-----+------------+
| 39 | 2014-09-17 |
| 46 | 2014-09-18 |
| 40 | 2014-09-19 |
| 48 | 2014-09-19 |
| 45 | 2014-09-20 |
| 47 | 2014-12-05 |
+-----+------------+
This is the HTML I want to generate:
Contract from 17/09/2014 to 20/09/2014
UIDS: 39-46-40-48-45
Contract from 05/12/2014
UIDS: 47
This is my sourcecode
<?php
$output = '';
$list = array();
$lastitem = $lastdate = null;
$query = 'SELECT * FROM project_dates';
$sth = $dbh->prepare($query);
$sth->execute();
if($sth->rowCount() > 0) {
$i = 0;
while($row = $sth->fetch()) {
// CURRENT DATE
$date = new DateTime($row['date']);
// STORAGE
$item = array(
'date' => array(),
'var' => $row['uid'], // A '-' delimited variable of all the uids in the range (40-41-...)
'uids' => array() // An array of all the uids in the range
);
// IF THE DATE DIFF IS LESS THAN OR EQUAL TO ONE DAY
if ($item['date'] === $lastitem['date'] && $date->diff($lastdate)->days <= 1) {
// Problem here: looking for last date in set!
$list[$i-1]['date']['end'] = $date;
//Add current uid to the '-' delimited variable of uids of this range
$list[$i-1]['uid'] = $list[$i-1]['uid'].'-'.$item['uid'];
// Add current uid to the array of uids of this range
array_push($list[$i-1]['uids'],$item['uid']);
} else {
// Next range
$list[$i] = $item;
$list[$i]['date']['start'] = $date;
$lastitem = $item;
$lastdate = $date;
array_push($list[$i]['uids'],$item['uid']);
$i++;
}
}
}
if(count($list)){
// Show text with first date and last date of the range
$output .= 'Contract from '.$item['date']['start']->format('d/m/Y');
$output .= isset($item['date']['end']) ? ' to ' . $item['date']['end']->format('d/m/Y') : '';
$output .= '<br />Uids: '.$item['var'];
}
foreach ($list AS $item) {
// Loop over the dates in this range
$output .= $item['date'].'<br />';
}
if(count($list)) {
// Line under this range
$output .= '<hr />';
}
echo $output;
?>
For some reason, my code returns 4 ranges instead of 2. I've been trying to figure out for hours why. Can someone help me? This is the faulty HTML:
Contract from 17/09/2014 to 18/09/2014
UIDS: 39-46
Contract from 19/09/2014
UIDS: 40
Contract from 19/09/2014 tot 20/09/2014
UIDS: 48-45
Contract van 05/12/2014
UIDS: 47
Can anyone be of assistance?
I'd like to convert base 10 numbers to base 31
I would like to use only these characters: 23456789abcdefghjkmnpqrstuvwxyz
As you can see, 5 characters are excluded (i don't need these): 1 0 o l i
The function I have now is below but of course it doesn't work. When 2 is input it outputs 4. The output for tenTo31(2) should be 2
function tenTo31($num)
{
$out = "";
$alpha = "23456789abcdefghjkmnpqrstuvwxyz";
while($num > 30)
{
$r = $num % 31;
$num = floor($num / 31) - 1;
$out = $alpha[$r] . $out;
}
return $alpha[$num] . $out;
}
Any ideas on how to make this work?
This is a blind guess at what you want:
$alpha = "yz23456789abcdefghjkmnpqrstuvwx";
There's a built-in function for converting from one base to another, base_convert(). The alphabet is fixed, but you can use strtr() to replace those digits with your own.
"The output for tenTo31(2) should be 2": One possibility is to make '2' the third symbol again.
function tenTo31($num) {
static $from = "0123456789abcdefghijklmnopqrstu";
static $to = "yz23456789abcdefghjkmnpqrstuvwx";
return strtr(base_convert($num, 10, 31), $from, $to);
}
for($i=0; $i<31; $i++) {
echo $i, '=', tenTo31($i), ' | ';
if ( 9===$i%10 ) echo "\n";
}
prints
0=y | 1=z | 2=2 | 3=3 | 4=4 | 5=5 | 6=6 | 7=7 | 8=8 | 9=9 |
10=a | 11=b | 12=c | 13=d | 14=e | 15=f | 16=g | 17=h | 18=j | 19=k |
20=m | 21=n | 22=p | 23=q | 24=r | 25=s | 26=t | 27=u | 28=v | 29=w |
30=x |
edit:
To convert the base(31) number back to decimal you first have to reverse the translation (strtr) and then call base_convert(.., 31, 10). You can combine the conversion from and to base(31) in a single function.
function convert_ten_31($num, $numIsDecimal) {
static $default = "0123456789abcdefghijklmnopqrstu";
static $symbols = "yz23456789abcdefghjkmnpqrstuvwx";
if ( $numIsDecimal ) {
return strtr(base_convert($num, 10, 31), $default, $symbols);
}
else {
return base_convert(strtr($num, $symbols, $default), 31, 10);
}
}
// testing
for($i=0; $i<10000; $i++) {
$x = convert_ten_31($i, true);
$x = convert_ten_31($x, false);
if ( $i!==(int)$x ) {
var_dump($i, $x);
die;
}
}
echo 'done.';
It's also easily possible to write a function like base_convert() yourself that take the symbols as parameter and thus having one flexible function instead of tenTo30(), tenTo31(), tenTo32(), ....
You aren't using the 1 and 0 characters, the first digit in your numbering system is 2 meaning 2 is the equivalent of 0 in base 10. 3 is equivalent to 1 in base 10 and 4 is equivalent to 2 in base 10.
Why are you taking modules by 32? You should use %31 and /31. In base 10 we are using modules by 10, so should be in base 31. But if we forget about this, I think your logic is correct. I can't understand why 2 in base 10 is equal to 4 in base 31 using your "modified digits".
While I'd encourage you to continue along with your algorithm for the learning exercise, consider using base_convert if you just need to get the job done.
The mapping according to http://www.crockford.com/wrmg/base32.html appears to be:
function symbolToEncode ($num) {
$out = "";
static $alpha = "0123456789ABCDEFGHJKMNPQRSTVWXYZ*~$=U";
while ($num >= 37) {
$r = $num % 37;
$num = floor ($num / 37);
$out = $out . $alpha[$r];
}
return $out . $alpha[$num];
}
function decodeToEncode ($str) {
static $from = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*~=$";
static $to = "0123456789ABCDEFGH1JK1MN0PQRSTUVWXYZABCDEFGH1JK1MN0PQRSTUVWXYZ*~=$";
return strtr ($str, $from, $to);
}
Though clearly the real challenge is to write a encodeToSymbol() function. I am not really a PHP expert (my $'s in the strings probably needs to be escaped somehow -- hints?), so I will leave that to others.