I need help sorting [Time] data from in this array in php. For a given day, the time is NOT in order.
Is there a way to sort this? Thanks.
Array ( [0] => Array ( )
[1] => Array (
[Server] => server1.name
[Date] => Sun Aug 22 2010
[Set] => db2.bak_lvm
[Time] => 06:00:02
[Duration] => 01:28:12
[Size] => 72.05 GB
[Status] => Succeeded )
[2] => Array ( [Server] => server1.name
[Date] => Sun Aug 22 2010
[Set] => db2.bak_lvm
[Time] => 00:00:03
[Duration] => 01:49:37
[Size] => 187.24 GB
[Status] => Succeeded )
[3] => Array ( [Server] => server1.name
[Date] => Sun Aug 22 2010
[Set] => db3.bak_lvm
[Time] => 23:00:03
[Status] => Unsuccessful )
[4] => Array ( [Server] => server1.name
[Date] => Sun Aug 22 2010
[Set] => db4.bak_lvm
[Time] => 04:00:03
[Duration] => 00:42:36
[Size] => 46.46 GB
[Status] => Succeeded )
Here's my php code, thus far:
<?php
$data = array();
$InputFile = file("test.txt");
foreach ($InputFile as $line){
preg_match_all("/([0-9])-([^=]+)=([^;]+);/", $line, $matches, PREG_SET_ORDER);
$LineData = array();
foreach ($matches as $information)
$LineData[$information[2]] = $information[3];
$data[] = $LineData;
}
$keys = array('Server', 'Date','Set','Time','Duration','Size','Status');
echo '<table id="stats"><tr>';
foreach ($keys as $column)
echo '<th>' . $column . '</th>';
echo '</tr>';
$counter=0;
foreach ($data as $row){
$counter ++;
$class = $counter % 2 === 0 ? 'alt1' : 'alt2';
echo '<tr class="' . $class . '">';
foreach ($keys as $column)
if (isset($row[$column])){
echo '<td>' . $row[$column];
} else {
echo '<td>' . '' . '</td>';
}
}
echo '</table>';
print_r($data);
?>
Updated: Latest sort after using suggested fix by Bill. [Time] is in order, but also need to have it sorted within [Date]
Array ( [0] => Array (
[Server] => server1.name
[Date] => Mon Aug 23 2010
[Set] => db2.bak_lvm
[Time] => 00:00:03
[Duration] => 01:50:24
[Size] => 187.24 GB
[Status] => Succeeded )
[1] => Array ( [Server] => server1.name
[Date] => Mon Aug 23 2010
[Set] => db3.bak_lvm
[Time] => 04:00:02
[Duration] => 00:42:28
[Size] => 46.47 GB
[Status] => Succeeded )
[2] => Array ( [Server] => server1.name
[Date] => Sun Aug 22 2010
[Set] => db3.bak_lvm
[Time] => 04:00:03
[Duration] => 00:42:36
[Size] => 46.46 GB
[Status] => Succeeded )
[3] => Array ( [Server] => server1.name
[Date] => Mon Aug 23 2010
[Set] => db1.bak_lvm
[Time] => 06:00:02
[Duration] => 01:28:24
[Size] => 72.05 GB
[Status] => Succeeded )
[4] => Array ( [Server] => server1.name
[Date] => Sun Aug 22 2010
[Set] => db4.bak_lvm
[Time] => 20:00:03
[Duration] => 04:17:57
[Size] => 426.60 GB
[Status] => Succeeded )
edit: Now that I understand your input data better, I've tested this script.
First I read the data file as you do, but I collect the data field by field directly into a two-dimensional array:
<?php
$data = array();
$InputFile = file("test.txt");
foreach ($InputFile as $line)
{
preg_match_all("/([0-9])-([^=]+)=([^;]+);/", $line, $matches, PREG_SET_ORDER);
foreach ($matches as $information)
{
$id = $information[1];
$field = $information[2];
$value = $information[3];
$data[$id][$field] = $value;
}
}
Next I sort the data array with a user-defined sorting function passed to usort(). Thanks to commenters for suggestions to make this function better.
function comparebydatetime($a, $b) {
$adate = strtotime($a["Date"]." ".$a["Time"]);
$bdate = strtotime($b["Date"]." ".$b["Time"]);
return $adate-$bdate;
}
usort($data, "comparebydatetime");
Now the data is sorted by date and time, so I can simply output it:
$keys = array("Server", "Date","Set","Time","Duration","Size","Status");
echo "<table id='stats'>\n";
echo "<tr>\n";
foreach ($keys as $column)
{
echo "<th>" . htmlspecialchars($column) . "</th>\n";
}
echo "</tr>\n";
$counter=0;
foreach ($data as $row)
{
$counter ++;
$class = $counter % 2 === 0 ? "alt1" : "alt2";
echo "<tr class='" . htmlspecialchars($class) . "'>\n";
foreach ($keys as $column)
{
echo "<td>";
if (isset($row[$column]))
{
echo htmlspecialchars($row[$column]);
}
echo "</td>\n";
}
echo "</tr>\n";
}
echo "</table>";
I've also added some other changes for better PHP style:
Be consistent about indentation.
Use curly-braces even for a block with one statement.
Use htmlspecialchars() for outputting dynamic data (including field names, CSS classes, etc.).
If you are on PHP5.3 already, you could use a Heap (manual|wiki) for this:
class SortByDateTimeDescending extends SplMaxHeap
{
public function compare($a, $b)
{
if(!empty($a['Date']) && !empty($a['Time']) &&
!empty($b['Date']) && !empty($b['Time']))
{
$timestampA = strtotime("{$a['Date']} {$a['Time']}");
$timestampB = strtotime("{$b['Date']} {$b['Time']}");
return $timestampA - $timestampB;
}
return 0;
}
}
$sorter = new SortByDateTimeDescending;
array_map(array($sorter, 'insert'), $data);
You can then foreach over $sorter or, if you want the heap back to an array, use
$sortedData = iterator_to_array($sorter);
If you are not on PHP5.3 yet, you can use the code in the compare function to usort() the data. The order will be reversed though (meaning Ascending). Iterating over the sorted array is easy.
You could also use a SortingIterator to go over the array directly.
Simply put : walk over your array and put each date as the key of each child, then ksort() your resulting array.
Don't forget to, if necessary, translate your date in DateTime before setting it as an array key, so that ksort() can work throught it:
$to_be_sorted = array();
foreach($array as $child) {
$date = new DateTime($child["date"].' '.$child["time"]);
$to_be_sorted[$date] = $child;
}
$sorted = ksort($to_be_sorted);
You'll loose your original keys (0,1,...,4) but I assume that it's not a problem ?
Related
I am parsing A JSON file in PHP using PHP Decode
$json= file_get_contents ("resultate.json");
$json = json_decode($json, true);
and then I am trying to loop through the results and display them
foreach($json as $zh){
$name = $zh[0]["VORLAGEN"][0]["JA_PROZENT"];
$JA = $zh[0]["VORLAGEN"][0]["VORLAGE_NAME"];
$kreis = $zh[0]["NAME"];
$kreis1 = $zh[22]["NAME"];
echo $name;
echo $JA;
echo $kreis;
echo $kreis1;
...}
but I receive only one element e.g. position 0 or position 22. I would like to receive all the results and display them in a list. Below you can see the array
Array
(
[GEBIETE] => Array
(
[0] => Array
(
[VORLAGEN] => Array
(
[0] => Array
(
[VORLAGE_NAME] => Kantonale Volksabstimmung über die Vorlage Steuergesetz (StG) (Änderung vom 1. April 2019; Steuervorlage 17)
[JA_STIMMEN_ABSOLUT] => 205
[STIMMBETEILIGUNG] => 28.11
[NEIN_STIMMEN_ABSOLUT] => 183
[VORLAGE_ID] => 2491
[JA_PROZENT] => 52.84
)
)
[NAME] => Aeugst a.A.
[WAHLKREIS] => 0
[BFS] => 1
)
[1] => Array
(
[VORLAGEN] => Array
(
[0] => Array
(
[VORLAGE_NAME] => Kantonale Volksabstimmung über die Vorlage Steuergesetz (StG) (Änderung vom 1. April 2019; Steuervorlage 17)
[JA_STIMMEN_ABSOLUT] => 1000
[STIMMBETEILIGUNG] => 26.15
[NEIN_STIMMEN_ABSOLUT] => 851
[VORLAGE_ID] => 2491
[JA_PROZENT] => 54.02
)
)
[NAME] => Affoltern a.A.
[WAHLKREIS] => 0
[BFS] => 2
)
[2] => Array
(
[VORLAGEN] => Array
(
[0] => Array
(
[VORLAGE_NAME] => Kantonale Volksabstimmung über die Vorlage Steuergesetz (StG) (Änderung vom 1. April 2019; Steuervorlage 17)
[JA_STIMMEN_ABSOLUT] => 661
[STIMMBETEILIGUNG] => 30.98
[NEIN_STIMMEN_ABSOLUT] => 454
[VORLAGE_ID] => 2491
[JA_PROZENT] => 59.28
)
)
[NAME] => Bonstetten
[WAHLKREIS] => 0
[BFS] => 3
)
can you please tell me how to print all the elements of this array?
There is GEBIETE layer in your json, so change foreach($json as $zh) to foreach($json["GEBIETE"] as $zh) will works.
You can nest multiple foreach:
$root = $json['GEBIETE'];
foreach ($root as $elem) {
foreach ($elem as $key => $value) {
// VORLAGEN is an array of its own so if you want to print the keys you should foreach this value as well
if(is_array($value)) {
foreach ($value[0] as $k => $v) {
echo $k."\t".$v;
}
}
else {
echo $value;
}
}
}
So I have a JSON output here https://squad-servers.com/api/?object=servers&element=detail&key=fupxq9hl1vkxb4yxhkggada7e0jz8p6w1
What I'd like to do is get this into a HTML Table to create my own status page as such, this is where I got with it.
<?php
$json=file_get_contents("https://squad-servers.com/api/?object=servers&element=detail&key=fupxq9hl1vkxb4yxhkggada7e0jz8p6w1");
$data = json_decode($json);
print_r($data);
?>
stdClass Object
(
[id] => 2272
[name] => [ZXD] Zulu X-Ray Delta EU/UK #2
[address] => 164.132.202.16
[port] => 7797
[private] => 0
[password] => 0
[query_port] => 27175
[location] => United Kingdom
[hostname] => Zulu X-Ray Delta EU/UK #2
[map] => Kokan AAS v1
[is_online] => 0
[players] => 0
[maxplayers] => 72
[version] => a-8.8.116.11628
[platform] => windows
[uptime] => 97
[score] => 4
[rank] => 81
[votes] => 0
[favorited] => 0
[comments] => 0
[url] => https://squad-servers.com/server/2272/
[last_check] => December 7th, 2016 08:50 AM EST
[last_online] => December 7th, 2016 07:25 AM EST
)
But how can I get this into a table, so I can echo / print out each part of the array?
Many thanks,
$tbl = "<table><tr><th>".implode('</th><th>',array_keys((array)$data))."</th></tr>";
$tbl .= "<tr><td>".implode('</td><td>',(array)$data)."</td></tr></table>";
print $tbl;
...on way to rome.
$head=array();
$body=array();
foreach($data as $k=>$v){
$head[]="<th>$k</th>";
$body[]="<td>$v</td>";
}
print "<table><tr>".implode('',$head)."</tr><tr>".implode('',$body)."</tr></table>";
...another way.
(every used function can be found at php.net)
This will only work on your example. Not every json output can be easy printed into an html-table.
You can print each value using foreach:
foreach ($data as $key => $value) {
echo $value;
}
http://php.net/manual/en/control-structures.foreach.php
All you need is to call print_r($data->name); so echo $data->name with current api call.
if you have more than one result:
<table>
<?php foreach ($object as $value) {
echo '<tr>';
echo '<td>'.$value->name.'</td>';
echo '<td>'.$value->address.'</td>';
echo '<td>'.$value->hostname.'</td>';
echo '<td>'.$value->uptime.'</td>';
echo '</tr>';
}
}
?>
</table>
json_decode has an optional second parameter determining whether you want to have an associated array. This parameter is false by default and therefore you get a standard object, which is much more difficult to handle. Instead, make sure that you have an associated array:
$data = json_decode($json, true);
foreach ($data as $key => $value) {
//Do something with $key and $value
}
I have a multidimensional array of data that is presented as follows:
Array
(
[0] => Array
(
[CallID] => 793415338
[StartTime] => 2016-10-04 17:21:53
[CallingNo] => +15555555555
[queue1_time] => 94
)
[1] => Array
(
[CallID] => 1718936847
[StartTime] => 2016-10-04 17:29:41
[CallingNo] => +15555555556
[queue1_time] => 64
[queue2_time] => 96
)
[2] => Array
(
[CallID] => 497342634
[StartTime] => 2016-10-04 17:34:57
[CallingNo] => +15555555557
[queue4_time] => 47
)
[3] => Array
(
[CallID] => 1298245252
[StartTime] => 2016-10-04 17:35:33
[CallingNo] => +15555555558
[queue1_time] => 5
)
[4] => Array
(
[CallID] => 1214106933
[StartTime] => 2016-10-04 17:35:38
[CallingNo] => +15555555559
[queue1_time] => 53
[queue2_time] => 31
)
....
)
I would like to parse all of the data in this array and convert it to a csv with a header above each set of array values that have matching complete key sets. Output would look like the following:
CallID,StartTime,CallingNo,queue1_time
793415338,2016-10-04 17:21:53,+15555555555,94
1298245252,2016-10-04 17:35:33,+15555555558,5
CallID,StartTime,CallingNo,queue1_time,queue2_time
1718936847,2016-10-04 17:29:41,+15555555556,64,96
1214106933,2016-10-04 17:35:38,+15555555559,53,31
CallID,StartTime,CallingNo,queue4_time
497342634,2016-10-04 17:34:57,+15555555557,47
Any further tips or tricks to shorten this code would be greatly appreciated!
I was able to get this functional with the following code but I am guessing there is a simpler more efficient method to perform this task:
$key_array = array();
foreach (array_keys($overflow_array) as $paramName){
foreach ($overflow_array[$paramName] as $key => $value){
$key_array[$paramName][] = $key;
}
}
$key_array = array_map("unserialize", array_unique(array_map("serialize", $key_array)));
function array_keys_exist($keys, $array){
if (count($keys) != count($array)){
return false;
}
foreach($keys as $num => $key){
if(!array_key_exists($key, $array))return false;
}
return true;
}
$output = fopen('php://temp/maxmemory:1048576', 'w');
if($output === FALSE) {
die('Failed to open temporary file');
}
foreach ($key_array as $keyset => $value){
$keys = array_values($value);
fputcsv($output, $keys);
foreach ($overflow_array as $oflow => $oflow_key){
if (array_keys_exist($keys, $overflow_array[$oflow]) == true){
fputcsv($output, $overflow_array[$oflow]);
}
}
}
rewind($output);
$csv = stream_get_contents($output);
fclose($output);
print_r($csv);
I have tried to get the below code to work for a good couple of hours, but just don't succeed.
I have this date array:
Array ( [0] => Array ( [0] => 2007 )
[1] => Array ( [0] => 2008 )
[2] => Array ( [0] => 2009 )
...
)
and this plusMinus one:
Array ( [0] => Array ( [plus] => 2 [date] => 2007 )
[1] => Array ( [minus] => 1 [date] => 2008 )
[2] => Array ( [minus] => 1 [date] => )
[3] => Array ( [plus] => 1 [date] => 2010 [minus] => 1 )
)
I have been trying to combine them into this:
Array ( [0] => Array ( [date] => 2007 [plus]=> 2)
[1] => Array ( [date] => 2008 [minus]=> 1)
[2] => Array ( [date] => 2009 [plusMinus]=> 0)
[3] => Array ( [date] => 2010 [plus] => 1 [minus]=>1 )
...
)
So basically I want to check if a value of the date array exists in the plusMinus array. If true the date and values from the plusMinus array shall replace the entry in the date array.
If false, the original date array entry is complemented by a [plusMinus] => 0 key-value pair.
The way I have tried to do it is this:
foreach ($filler as $key1 => $value1)
{
foreach ($plusMinus as $key2 => $value2)
{
if ($value1['0'] !== $value2['date'])
{
$value1['plusMinus'] = '0';
$result2[$key1][] = $value1;
}
elseif ($value1['0'] == $value2['date'])
{
if (array_key_exists('plus',$value2))
{
$value1['plus'] = $value2['plus'];
$result2[$key1][]=$value1;
}
elseif(array_key_exists('minus',$value2))
{
$value1['minus'] = $value2['minus'];
$result2[$key1][]=$value1;
}
elseif(array_key_exists('minus',$value2) &&
array_key_exists('plus',$value2))
{
}
}
}
}
$valuesComplete = array();
foreach ($result2 as $value) {
$result2 = $value['0'];
array_push($valuesIncomplete, $result2);
}
return $valuesComplete;
Instead of the desired outcome described above I get this:
Array ( [0] => Array
( [0] => 2007 [plus] => 2 )
[1] => Array ( [0] => 2008 [plusMinus => 0 )
[2] => Array ( [0] => 2009 [plusMinus] => 0 )
[3] => Array ( [0] => 2010 [plusMinus] => 0 )
[4] => Array ( [0] => 2011 [plusMinus] => 0 )
[5] => Array ( [0] => 2012 [plusMinus] => 0 )
[6] => Array ( [0] => 2013 [plusMinus] => 0 )
)
What am I missing? Thanks for any help!
Unfortunately, because of the input data format, I can't see any way to do this that doesn't involve an O(n + m + p) operation. But no matter, you gotta do what you gotta do.
Firstly I would start by filtering the useless elements from the PlusMinus array. Since it's already fairly close to the desired output format, it makes sense to use this as the base of the result.
$temp = array();
foreach ($plusMinus as $item) {
if (!empty($item['date'])) {
$temp[$item['date']] = $item;
}
}
Notice that I used the date as the index of the temporary array we're using to build the result. This is to allow you to easily ensure that the result array is in the correct order, and to quickly check whether an item needs to be added from the Filler array.
Next, we need to add any missing elements from the Filler array:
foreach ($filler as $item) {
if (!isset($temp[$item[0]])) {
$temp[$item[0]] = array(
'date' => $item[0],
'plusMinus' => 0
);
}
}
Now all the data is in the array in the correct format, we just need to sort it:
ksort($temp);
...and get convert it back to an indexed array:
return array_values($temp);
No need for the performance killing nested loops or complex flow control.
See it working
As I understood you need to add years that not in second array but in first?
In that case you can do:
foreach ($filler as $key1 => $value1)
{
$ok = false;
foreach ($plusMinus as $key2 => $value2)
{
if($value2['date']==$value1[0])
{
$ok = true;
break;
}
}
if(!$ok)
{
$plusMinus[$value1[0]]=array('date'=>$value1[0], 'plusMinus'=>0);
}
}
<?php
$a1 = array(array( 2007 ),
array( 2008 )
);
$a2 = array(array('plus'=>1, 'date'=>2007),
array('minus'=>1,'date'=>2008),
array('plus'=>1, 'minus'=>1, 'date'=>2008)
);
$r = array();
foreach($a1 as $k1=>$d1) {
$year = $d1[0];
foreach( $a2 as $k2=>$d2 ) {
if( $d2['date'] == $year ) {
$r[$year]['date'] = $year;
if(isset($d2['plus'])) {
$r[$year]['plus'] = $d2['plus'];
}
if(isset($d2['minus'])) {
$r[$year]['minus'] = $d2['minus'];
}
}
}
}
print_r($r);
and result
Array
(
[2007] => Array
(
[date] => 2007
[plus] => 1
)
[2008] => Array
(
[date] => 2008
[minus] => 1
[plus] => 1
)
)
$ar1 = array( array(2007), array(2008), array(2009), array(2010) );
$ar2 = array(
array("date"=>2007, "plus"=>2),
array("date"=>2008, "minus"=>1),
array("date"=>"", "minus"=>1),
array("date"=>2010, "plus"=>1, "minus"=>1)
);
foreach($ar2 as $key=>$val){
if(isset($ar1[$key][0]))
$val["date"] = $ar1[$key][0];
$ar2[$key] = $val;
}
I am not sure if I understand you correctly but this works fine...
It will work only if you are sure that your both arrays "date" equals one to other..
This is what I came up with:
To not create the product of both arrays (foreach inside foreach), I first index the $plusMinus array with the date. That will allow to test quickly if a year exists or not:
$years = array_combine(array_column($plusMinus, 'date'), $plusMinus);
This uses the array_column() function of PHP 5.5, if you don't have it you can easily create it your own.
After doing that it is exactly how you wrote it in your own words:
foreach($date as &$entry)
{
list($year) = $entry;
$entry = array('date' => $year);
// check if a value of the date array exists in the plusMinus array.
if (isset($years[$year])) {
// If true the date and values from the plusMinus array shall replace the entry in the date array
$entry += $years[$year];
} else {
// If false, the original date array entry is complemented by a [plusMinus] => 0 key-value pair.
$entry += array('plusMinus' => 0);
}
}
unset($entry);
See it i action.
This will work just fine.
I did not at all understand your question, but if i got it this is the way:
First make your $datearray more understandable like this:
$dateArray = array(2007,2008,2009,2010);
$plusMinus = array(
array( 'plus' => 2 ,'date' => 2007),
array( 'minus' => 1 ,'date' => 2008),
array ( 'minus' => 1 , 'date' => '' ),
array ( 'plus' => 1 , 'date' => 2010 , 'minus' => 1 )
);
You can make it multidimensional later;
After that:
foreach($dateArray as $k=>$v)
{
if(in_array($v,$plusMinus[$k]))
{
$filler[$k] = $plusMinus[$k];
}
else{
if(empty($plusMinus[$k]['date']))
{
$filler[$k]['date']= $v;
$filler[$k]['plusMinus'] = 0;
}
}
}
This is simple and clean, understandable way with very little code if your arrays will always have the structure you described, meaning the plusMinus values for 2007 are in the cell [0] and the 2007 in the dateArrays is also in the cell [0] like you have shown. I hope i could help.
I have a an array:
Array
(
[0] => Array
(
[id] => 53
[product] => something
[price] => £78
[quantity] => 23
[time] => 2011-07-15 20:29:21
)
[1] => Array
(
[id] => 52
[product] => product
[price] => £89
[quantity] => 1
[time] => 2011-07-14 00:51:57
)
[2] => Array
(
[id] => 51
[product] => product
[price] => £89
[quantity] => 1
[time] => 2011-07-14 00:51:37
))
I got this using the following sql statement:
select * from some_table GROUP BY time DESC
I want to display the results ordered by date, with the date as a heading:
e.g.
**2011-07-15**
all array elements for above date go here
**2011-07-15**
all array elements for above date go here
I thought about doing a seperate statement for each seperate day, but that sounds wrong. Is there a better way?
ORDER BY Time in your query, like this:
select * from some_table ORDER BY time DESC
Then loop in PHP:
$last_date = 0;
while($row = mysql_fetch_assoc($result)){
$date = date('Y-m-d', strtotime($row['time']));
if($date != $last_date)
echo '**'.$date.'**';
$last_date = $date;
echo '<br />';
echo 'Id: '.$row['Id'];
echo 'Product: '.$row['product'];
echo 'Price: '.$row['price'];
echo 'Quantity: '.$row['quantity'];
echo '<br /><br />';
}
If you're ouputting to a console instead of an HTML page then replace the '<br \>' with "\n"
<?
$arrDate = Array
(
[0] => Array
(
[id] => 53
[product] => something
[price] => £78
[quantity] => 23
[time] => 2011-07-15 20:29:21
);
$currentDate = null;
foreach ($arrDate as $item) {
if ($item["time"] == $currentDate) {
// print details
}
else {
$currentDate = $arrDate["time"];
// print date header.
// print details
}
}
?>