这是我之前遇到的一个问题,我还没有找到一个优雅的解决方案,所以我想我会请求SO的帮助。
我正在遍历一个数组并打印掉该数组中的一些信息,并且无法弄清楚如何打印我的开始和结束<div>
标记。下面是一个示例表和所需的输出以及我当前算法的基本实现。我希望有人能指出我更好的打印数据算法。我在PHP中这样做,但通用算法会很精彩。
非常感谢!
表格(为了清晰起见,添加间距)
Choice ID Choice Body Question ID Question Body --------------------------------------------------------------------- 1 Yes, very much 1 Do you like sandwiches? 2 Somewhat 1 Do you like sandwiches? 3 Not at all 1 Do you like sandwiches? 4 I hate them 1 Do you like sandwiches? 5 Sure, why not 2 Do you like apples? 6 Yesh, I guess 2 Do you like apples? 7 What are those 2 Do you like apples? 8 Yes, very much 3 Do you like chips? 9 Not at all 3 Do you like chips?
期望输出:
<div class='question' id='1'>
<p>Do you like sandwiches?</p>
<div class='choices'>
<span class='choice'>Yes, very much</span>
<span class='choice'>Somewhat</span>
<span class='choice'>Not at all</span>
<span class='choice'>I hate them</span>
</div>
</div>
<div class='question' id='2'>
<p>Do you like apples?</p>
<div class='choices'>
<span class='choice'>Sure, why not</span>
<span class='choice'>Yeah, I guess</span>
<span class='choice'>What are those</span>
</div>
</div>
<div class='question' id='3'>
<p>Do you like chips?</p>
<div class='choices'>
<span class='choice'>Yes, very much</span>
<span class='choice'>Not at all</span>
</div>
</div>
我目前正在使用的基本算法:
$last_id = null;
while ($choice = pg_fetch_array($choices)) {
if ($last_id != $choice['id']) {
if ($last_id != null) {
echo "</div>";
}
echo "<div id='$choice[id]'>";
}
// Print choice info
$last_id = $choice['id'];
}
if ($last_id != null) {
echo "</div>";
}
注意:我使用这种方式的原因是出于优化目的。这只需要一个数据库查询,并且会有很多结果。我不想对每个问题进行查询以获得它的选择。我知道如何做到这一点,它更容易,但不是很有效或快速。
编辑1:固定代码,算法现在有效,但仍不漂亮。对于评论者:pg_fetch_array()
是一个PostgreSQL函数,基本上创建一个关联数组。非常类似于一个对象。您只需要$choice['id']
或$choice['body']
。
答案 0 :(得分:1)
如果新读取的id与上一个不同(并且最后一个不为空),则应在循环开始时打印结束</div>
。
此外,在循环之后(再次,如果最后一个id不为null,这意味着根本没有组),则需要关闭最后一个组。
答案 1 :(得分:1)
按类似值对项目进行分组很难称为算法。如果不是其他的话,它更像是一种编码模式。
编码的好方法是将机制与意图分开。在这种情况下,机制是如何跟踪键值以查找分组边界,目的是为每个连续组输出HTML。
Python for instance有一个名为groupby的库函数来完成这个。所以在Python中,代码看起来像这样(忽略了为此使用模板库的事实):
from itertools import groupby
def question_from_row(row):
return dict(id=row['question_id'], body=row['question_body'])
for question, choices in groupby(questions, key=question_from_row):
print('<div class="question" id="%s">' % question['id'])
print(' <p>%s</p>\n' % question['body'])
print(' <div class="choices">')
for choice in choices:
print('<span class="choice">%s</span>' % choice['choice_body'])
print(' </div>')
print('</div>')
据我所知,PHP并没有像内置的那样,但是一个简单的实现非常简单:
function array_groupby($input, $keyfunc) {
$output = array();
$last_key = null;
$current = null;
foreach ($input as $item) {
$item_key = $keyfunc($item);
if ($last_key === null || $item_key != $last_key) {
if ($current !== null) {
$output[] = $current;
}
$last_key = $item_key;
$current = array();
}
$current[] = $item;
}
if ($current !== null) {
$output[] = $current;
}
return $output;
}
这将是您包含的典型库代码。处理输出的代码变得相当简单。与分组的完成方式完全隔离。例如,您可以更改array_groupby以返回实现Iterator接口的对象,并且只从输入iterable中延迟提取。
$questions = array_groupby(pg_fetch_array($choices),
function($choice) { return $choice['id']; });
foreach ($questions as $choices) {
$question = $choices[0];
echo '<div class="question" id="'.$question['id'].'">';
echo '<p>'.$question['body'].'</p>';
echo '<div class="choices">';
foreach ($choices as $choice) {
echo '<span class="choice">'.$choice['choice_body'].'</span>';
}
echo '</div>';
echo '</div>';
}
此示例使用PHP 5.3闭包功能。在旧版本中,指定提取分组键的功能会稍微有点丑陋,可能需要面向对象的方法。
答案 2 :(得分:0)
因为我已经完成了任何PHP,但我会尝试这样的事情......
// print leading div for very first in array
echo "<div>";
$last_question = null;
while ($choice = pg_fetch_array($choices)) {
// print choice info
echo "<span ...>";
if($last_question != $choice['question_id'])
{
// print trailing div for last one
echo "</div>";
// print leading div for next one
echo "<div>";
}
// set last question
$last_question = $choice['question_id'];
}
// print trailing div for very last in array
echo "</div>";
可能需要改进以确保它最后不会打印额外的div。