简明现代魔法 -> PHP服务器脚本 -> 用PHP数组实现交叉表

用PHP数组实现交叉表

2010-08-03

什么是交叉表

"交叉表"对象是一个网格,用来根据指定的条件返回值。数据显示在压缩行和列中。这种格式易于比较数据并辨别其趋势。它由三个元素组成:

  • 摘要字段

"交叉表"中的行沿水平方向延伸(从一侧到另一侧)。在上面的示例中,"手套"(Gloves) 是一行。

"交叉表"中的列沿垂直方向延伸(上下)。在上面的示例中,"美国"(USA) 是一列。

汇总字段位于行和列的交叉处。每个交叉处的值代表对既满足行条件又满足列条件的记录的汇总(求和、计数等)。在上面的示例中,"手套"和"美国"交叉处的值是四,这是在美国销售的手套的数量。

"交叉表"还可以包括若干总计:

每行的结尾是该行的总计。在上面的例子中,该总计代表一个产品在所有国家/地区的销售量。"手套"行结尾处的值是 8,这就是手套在所有国家/地区销售的总数。 注意:总计列可以出现在每一行的开头。

每列的底部是该列的总计。在上面的例子中,该总计代表所有产品在一个国家/地区的销售量。"美国"一列底部的值是四,这是所有产品(手套、腰带和鞋子)在美国销售的总数。注意:总计列可以出现在每一行的顶部。

"总计"(Total) 列(产品总计)和"总计"(Total) 行(国家/地区总计)的交叉处是总计。在上面的例子中,"总计"列和"总计"行交叉处的值是 12,这是所有产品在所有国家/地区销售的总数。

用PHP实现交叉表类

/**
 * 基本交叉表
 * @author hugh
 *
 */
class Pivot
{
    
    private $HORIZONTAL_TOTAL_FIELD = 'total';
    private $VERTICAL_TOTAL_FIELD = 'total';
    
    private $data;
    
    private $topPivot;
    private $leftPivot;
    private $measure;
    
    private $horizontalColumn = array ();
    private $verticalColumn = array ();
    
    private $pivotValue = array ();
    
    private $isHorizontalTotal = true;
    private $isVerticalTotal = true;
    
    private $horizontalTotal = null;
    private $verticalTotal = null;
    
    private $title = 'PivotTab';
    
    /**
     * 初始化交叉表
     */
    private function InitPivot()
    {
        $this->topPivot;
        foreach ( $this->data as $d )
        {
            $this->horizontalColumn [] = $d [$this->leftPivot];
            $this->verticalColumn [] = $d [$this->topPivot];
        }
        
        $this->horizontalColumn = array_unique ( $this->horizontalColumn );
        $this->verticalColumn = array_unique ( $this->verticalColumn );
        
        $reasult = array ();
        foreach ( $this->horizontalColumn as $h )
        {
            foreach ( $this->verticalColumn as $v )
            {
                $this->pivotValue [$h] [$v] = 0;
            }
        }
    
    }
    
    /**
     * 填充数据
     */
    private function fillData()
    {
        foreach ( $this->data as $row )
        {
            $this->pivotValue [$row [$this->leftPivot]] [$row [$this->topPivot]] += $row [$this->measure];
        }
        if ($this->isHorizontalTotal)
        {
            $this->setHorizontalTotal ();
        }
        if ($this->isVerticalTotal)
        {
            $this->setVerticalTotal ();
        }
    }
    
    /**
     * 设置纵向合计
     */
    private function setVerticalTotal()
    {
        $this->verticalColumn [] = $this->VERTICAL_TOTAL_FIELD;
        foreach ( $this->horizontalColumn as $i )
        {
            $rowsum = 0;
            foreach ( $this->verticalColumn as $j )
            {
                $rowsum += $this->pivotValue [$i] [$j];
            }
            $this->pivotValue [$i] [$this->TOTAL_FIELD] = $rowsum;
        }
    }
    
    /**
     * 设置横向合计
     */
    private function setHorizontalTotal()
    {
        $this->horizontalColumn [] = $this->HORIZONTAL_TOTAL_FIELD;
        foreach ( $this->verticalColumn as $i )
        {
            $rowsum = 0;
            foreach ( $this->horizontalColumn as $j )
            {
                $rowsum += $this->pivotValue [$j] [$i];
            }
            $this->pivotValue [$this->HORIZONTAL_TOTAL_FIELD] [$i] = $rowsum;
        }
    }
    
    /**
     * 渲染
     */
    function Render()
    {
        echo '<pre>';
        print_r ( $this->pivotValue );
    }
    
    /**
     * 渲染为table
     */
    function RenderToTable()
    {
        $resault = "<table border='1' width='250'>\n";
        $resault .= "<tr><td>$this->title</td>\n";
        
        foreach ( $this->verticalColumn as $value )
        {
            $resault .= "<td>$value</td>\n";
        }
        $resault .= "</tr>\n";
        
        foreach ( $this->horizontalColumn as $i )
        {
            $resault .= "<tr><td>$i</td>\n";
            
            foreach ( $this->pivotValue [$i] as $value )
            {
                $resault .= "<td>$value</td>\n";
            }
            $resault .= "</tr>\n";
        }
        
        $resault .= "</table>";
        
        return $resault;
    }
    
    /**
     * 构造交叉表
     * @param $data 数据源
     * @param $topPivot 头栏目字段
     * @param $leftPivot 左栏目字段
     * @param $measure 计算量
     */
    function __construct(array $data, $topPivot, $leftPivot, $measure)
    {
        $this->data = $data;
        $this->leftPivot = $leftPivot;
        $this->topPivot = $topPivot;
        $this->measure = $measure;
        $this->horizontalColumn = array ();
        $this->verticalColumn = array ();
        
        $this->InitPivot ();
        $this->fillData ();
    }

}

重点在于InitPivot方法及fillData方法。InitPivot里面保证了所有的item都会有值(默认为0)。fillData方法使用选择填充添加的方法,将数据填充入我们装数据的$pivotValue里面。然后喜欢怎么输出都可以了。

随机文章推荐
网站分类


注:如需转载本文,请注明出处(原文链接),谢谢。更多精彩内容,请进入简明现代魔法首页。

进入新博客
喜欢本文,就分享它吧
给我留言
您的名字:
您的邮件:
您的网站:


 

copyright © 2009 简明现代魔法    学习、分享、进步

power by Gonn 感谢所有关心和支持本站的朋友们