在 PHP 中循环获取数组值
Get Array values in a loop in PHP
我有一个数组 $data 组成如下:
$data[$k]['id'] = $row['iddevice'];
$data[$k]['temp_00'] = $row['temp_00'];
$data[$k]['temp_01'] = $row['temp_01'];
$data[$k]['temp_02'] = $row['temp_02'];
$data[$k]['temp_03'] = $row['temp_03'];
$data[$k]['temp_04'] = $row['temp_04'];
这个数组我只有两个元素,所以echo count($data);
return2
我正在使用 Morris.js 创建折线图,下面是工作代码示例:
$(function() {
Morris.Line({
element: 'morris-area-chart',
data: [
{ y: '00h', 1:57, 2:41},
{ y: '01h', 1:62, 2:98},
{ y: '02h', 1:44, 2:43},
{ y: '03h', 1:67, 2:84},
],
xkey: 'y',
parseTime:false,
ykeys: [1,2,3],
pointSize: 2,
hideHover: 'auto',
labels: ['Capteur X', 'Capteur Y']
});
我的问题是,一旦我尝试使用 PHP 来使用我的 $data
中的值,它就不起作用,图表不会加载任何值。
Morris.Line({
element: 'morris-area-chart',
data: [
{ y: '00h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_00'],2); $i++; }?>},
{ y: '01h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_01'],2); $i++; }?>},
{ y: '02h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_02'],2); $i++; }?>},
{ y: '03h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_03'],2); $i++; }?>},
],
对我来说,算法很好:
- $i 等于 0
- 而
$i
小于或等于 count($data)-1
(所以 2-1 = 1 所以我们应该留在循环中两次)
- 显示该元素的 ID 和温度值
- 将
$i
增加一
我在想什么或做错了什么?
此外,当我将 $i
初始化为 1 而不是 0 时,我可以获得 $data
数组
中第二个条目的值
(我更愿意说我不是开发人员,所以这段代码可能不是我同意的最干净的代码)
编辑:
粘贴到 $data
的 var_dump
:http://pastebin.com/dYNtLxqX
使用 Forbs 解决方案时的屏幕截图(图表根本无法加载):
我用来填充 $data
数组的 SQL 查询:
select iddevice, data.ip, type, description,
avg(case when hour(date) = 00 then temp end) as temp_00,
avg(case when hour(date) = 01 then temp end) as temp_01,
avg(case when hour(date) = 02 then temp end) as temp_02,
...
avg(case when hour(date) = 22 then temp end) as temp_22,
avg(case when hour(date) = 23 then temp end) as temp_23
from data, device
where date >= '2017-03-20' and
date < '2017-03-21' and
device.ip = data.ip
group by ip
order by iddevice;
使用 while 循环使用此查询填充数组
$results = $conn->query($sql);
$k = 0;
$data = array();
while ($row = $results->fetch_assoc()) {
$data[$k]['temp_00'] = $row['temp_00'];
$data[$k]['temp_01'] = $row['temp_01'];
$data[$k]['temp_02'] = $row['temp_02'];
$data[$k]['temp_03'] = $row['temp_03'];
...
$k++;
}
你的问题在循环中
while ($i <= count($data)-1)
这应该是
while ($i <= (count($data)-1))
或者
while ($i < count($data))
效果更好
你可以进一步优化它。
Morris.Line({
element: 'morris-area-chart',
data: [
<?php
foreach($data as $sensor) {
foreach($sensor as $key => $value) {
if($key == 'id') {
$id = $value;
} else {
$tempTime[$key][$id] = $value;
}
}
}
$i = 0;
foreach($tempTime as $time) {
echo sprintf("{ y: '%02dh', ",$i);
foreach($time as $key => $value) {
echo sprintf("%d:%d, ",$key, round($value,2);
}
echo "},";
$i++;
}
?>
],
xkey: 'y',
parseTime:false,
ykeys: [1,2,3],
pointSize: 2,
hideHover: 'auto',
labels: ['Capteur X', 'Capteur Y']
});
这样,如果您的数组变大,您就不必重复自己。
说明
foreach
是一个遍历数组的函数。
第一个 foreach 循环只是对数组重新排序,以便在最后一个 foreach
循环中更容易使用(当您首先从 sql 创建数组时,您会适当地这样做,但是我从你的 post 看不出你是怎么做到的)
最后一个 foreach
循环只是打印出 Morris.line()
函数所需的字符串。希望这是有道理的。
这是我建议的另一种方法。它减少了重复代码,并最大限度地减少了 PHP/JS 混合。
首先,在从查询中获取行时,构建数组的方式略有不同:
while ($row = $results->fetch_assoc()) {
// Loop over each of the temp_x columns
for ($i=0; $i < 4; $i++) {
$x = str_pad($i, 2, '0', STR_PAD_LEFT);
// add the value for each temp_x to a temporary array, using time for a key
$temp = is_null($row["temp_$x"]) ? 'null' : round($row["temp_$x"], 2);
$times[$x][] = $row['iddevice'] . ':' . $temp;
}
}
接下来,格式化临时数组中每个数组的值
foreach ($times as $time => $temps) {
$data[] = "{ y: '{$time}h', " . implode(', ', $temps) . '}';
}
然后将$data
数组转换为字符串:
$data = implode(",\n", $data);
这样,您在 JS 部分需要的所有 PHP 是:
Morris.Line({
element: 'morris-area-chart',
data: [ <?php echo $data ?> ]
使用 json_encode
可能有更好的方法。如果您稍微更改 while
循环中的代码,该循环从您的数据库中获取行:
for ($i=0; $i < 4; $i++) {
$x = str_pad($i, 2, '0', STR_PAD_LEFT);
$temp = is_null($row["temp_$x"]) ? null : round($row["temp_$x"], 2);
$times[$x]['y'] = $x.'h';
$times[$x][$row['iddevice']] = $temp;
}
然后用json_encode
可以组成$data
。 (array_values
用于使用数字索引重新索引数组,因此它将在 JSON 输出中呈现为数组而不是对象。)
$data = json_encode(array_values($times));
在 JS 中:
Morris.Line({
element: 'morris-area-chart',
data: <?php echo $data ?>
// note: no [] brackets around $data in this version
这是否有效取决于是否所有键都是字符串,因为 JSON 键是字符串,所以你会得到像
这样的输出
{ "y": "01", "1": 17.62, "2": 19.52 }
而不是
{ y: '01', 1: 17.62, 2: 19.52 }
我认为它应该可以正常工作。
我有一个数组 $data 组成如下:
$data[$k]['id'] = $row['iddevice'];
$data[$k]['temp_00'] = $row['temp_00'];
$data[$k]['temp_01'] = $row['temp_01'];
$data[$k]['temp_02'] = $row['temp_02'];
$data[$k]['temp_03'] = $row['temp_03'];
$data[$k]['temp_04'] = $row['temp_04'];
这个数组我只有两个元素,所以echo count($data);
return2
我正在使用 Morris.js 创建折线图,下面是工作代码示例:
$(function() {
Morris.Line({
element: 'morris-area-chart',
data: [
{ y: '00h', 1:57, 2:41},
{ y: '01h', 1:62, 2:98},
{ y: '02h', 1:44, 2:43},
{ y: '03h', 1:67, 2:84},
],
xkey: 'y',
parseTime:false,
ykeys: [1,2,3],
pointSize: 2,
hideHover: 'auto',
labels: ['Capteur X', 'Capteur Y']
});
我的问题是,一旦我尝试使用 PHP 来使用我的 $data
中的值,它就不起作用,图表不会加载任何值。
Morris.Line({
element: 'morris-area-chart',
data: [
{ y: '00h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_00'],2); $i++; }?>},
{ y: '01h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_01'],2); $i++; }?>},
{ y: '02h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_02'],2); $i++; }?>},
{ y: '03h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_03'],2); $i++; }?>},
],
对我来说,算法很好:
- $i 等于 0
- 而
$i
小于或等于count($data)-1
(所以 2-1 = 1 所以我们应该留在循环中两次) - 显示该元素的 ID 和温度值
- 将
$i
增加一
我在想什么或做错了什么?
此外,当我将 $i
初始化为 1 而不是 0 时,我可以获得 $data
数组
(我更愿意说我不是开发人员,所以这段代码可能不是我同意的最干净的代码)
编辑:
粘贴到
$data
的var_dump
:http://pastebin.com/dYNtLxqX使用 Forbs 解决方案时的屏幕截图(图表根本无法加载):
我用来填充
$data
数组的 SQL 查询:select iddevice, data.ip, type, description, avg(case when hour(date) = 00 then temp end) as temp_00, avg(case when hour(date) = 01 then temp end) as temp_01, avg(case when hour(date) = 02 then temp end) as temp_02, ... avg(case when hour(date) = 22 then temp end) as temp_22, avg(case when hour(date) = 23 then temp end) as temp_23 from data, device where date >= '2017-03-20' and date < '2017-03-21' and device.ip = data.ip group by ip order by iddevice;
使用 while 循环使用此查询填充数组
$results = $conn->query($sql); $k = 0; $data = array(); while ($row = $results->fetch_assoc()) { $data[$k]['temp_00'] = $row['temp_00']; $data[$k]['temp_01'] = $row['temp_01']; $data[$k]['temp_02'] = $row['temp_02']; $data[$k]['temp_03'] = $row['temp_03']; ... $k++; }
你的问题在循环中
while ($i <= count($data)-1)
这应该是
while ($i <= (count($data)-1))
或者
while ($i < count($data))
效果更好
你可以进一步优化它。
Morris.Line({
element: 'morris-area-chart',
data: [
<?php
foreach($data as $sensor) {
foreach($sensor as $key => $value) {
if($key == 'id') {
$id = $value;
} else {
$tempTime[$key][$id] = $value;
}
}
}
$i = 0;
foreach($tempTime as $time) {
echo sprintf("{ y: '%02dh', ",$i);
foreach($time as $key => $value) {
echo sprintf("%d:%d, ",$key, round($value,2);
}
echo "},";
$i++;
}
?>
],
xkey: 'y',
parseTime:false,
ykeys: [1,2,3],
pointSize: 2,
hideHover: 'auto',
labels: ['Capteur X', 'Capteur Y']
});
这样,如果您的数组变大,您就不必重复自己。
说明
foreach
是一个遍历数组的函数。
第一个 foreach 循环只是对数组重新排序,以便在最后一个 foreach
循环中更容易使用(当您首先从 sql 创建数组时,您会适当地这样做,但是我从你的 post 看不出你是怎么做到的)
最后一个 foreach
循环只是打印出 Morris.line()
函数所需的字符串。希望这是有道理的。
这是我建议的另一种方法。它减少了重复代码,并最大限度地减少了 PHP/JS 混合。
首先,在从查询中获取行时,构建数组的方式略有不同:
while ($row = $results->fetch_assoc()) {
// Loop over each of the temp_x columns
for ($i=0; $i < 4; $i++) {
$x = str_pad($i, 2, '0', STR_PAD_LEFT);
// add the value for each temp_x to a temporary array, using time for a key
$temp = is_null($row["temp_$x"]) ? 'null' : round($row["temp_$x"], 2);
$times[$x][] = $row['iddevice'] . ':' . $temp;
}
}
接下来,格式化临时数组中每个数组的值
foreach ($times as $time => $temps) {
$data[] = "{ y: '{$time}h', " . implode(', ', $temps) . '}';
}
然后将$data
数组转换为字符串:
$data = implode(",\n", $data);
这样,您在 JS 部分需要的所有 PHP 是:
Morris.Line({
element: 'morris-area-chart',
data: [ <?php echo $data ?> ]
使用 json_encode
可能有更好的方法。如果您稍微更改 while
循环中的代码,该循环从您的数据库中获取行:
for ($i=0; $i < 4; $i++) {
$x = str_pad($i, 2, '0', STR_PAD_LEFT);
$temp = is_null($row["temp_$x"]) ? null : round($row["temp_$x"], 2);
$times[$x]['y'] = $x.'h';
$times[$x][$row['iddevice']] = $temp;
}
然后用json_encode
可以组成$data
。 (array_values
用于使用数字索引重新索引数组,因此它将在 JSON 输出中呈现为数组而不是对象。)
$data = json_encode(array_values($times));
在 JS 中:
Morris.Line({
element: 'morris-area-chart',
data: <?php echo $data ?>
// note: no [] brackets around $data in this version
这是否有效取决于是否所有键都是字符串,因为 JSON 键是字符串,所以你会得到像
这样的输出{ "y": "01", "1": 17.62, "2": 19.52 }
而不是
{ y: '01', 1: 17.62, 2: 19.52 }
我认为它应该可以正常工作。