Jinjin's profile试试看PhotosBlogListsMore Tools Help

Blog


    June 08

    没有变量和循环的语言 冒泡泡续

    XSLT是一种 functional programming language,函数被当作语言中的第一等公民,在这里只关注功能的定义而不是代码的执行次序,于是在 Imperative programming 中极重要的 loop 消失了,而且所谓的 variable 也变的了一旦定义便不可改变,这还叫作变量么?
     
     
    没有了循环,没有了可变量,一个原本简单的数组遍历该怎么实现呢?
     
     
    还是冒泡泡中的那个老问题,从一个正整数数组中找出最大值。
     
     
    若是在 Imperative programming language 中,我们可以设指针来遍历数组,设变量来记录每次的最大值:
    int returnValue = 0;
    for(int i=0; i<a.length;i++){
    if(int[i]>returnValue)
    returnValue=int[i];
    }
     
     
    可是在变量不可变,循环不可用的XSLT中呢?recursion with parameters.
     
     
    定义一个template,参数一为数组,参数二是最大值。每次进入 template 先判断参数一是否为空,若是则返回参数二;若否则递归,求出数组第二位至最后一位中的最大值,然后与参数二比较,返回二者中的最大值。
    <xsl:template name="getMaximum">
      <xsl:param name="nodes"/>
      <xsl:param name="max"/>
      <xsl:choose>
        <xsl:when test="not($nodes)">
          <xsl:value-of select="number($max)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="aNode" select="$nodes[1]"/>
          <xsl:call-template name="getMaximum">
            <xsl:with-param name="nodes" select="$nodes[position( ) > 1]"/>
            <xsl:with-param name="max">
              <xsl:choose>
                <xsl:when test="number($aNode) &gt; number($max) or string($max) = 'NaN'">
                  <xsl:value-of select="$aNode"/>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="$max"/>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:with-param>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>
     

     

    在XSLT中,一般的问题可以通过 xsl:for-each, xsl:apply-template 在特定的节点集上执行 select,当遇到标准XSLT不能解决的问题时,recursion 便是一个很好的选择。

     

    June 06

    冒泡泡

    比起 XSLT 1.0, 2.0 的功能强大了很多,尤其是新特性 grouping,遇到对条目分类计算的问题,三五行代码就能搞定。比如有一份图书列表,按作者对书目归类
    <xsl:for-each-group select="book/author" group-by="author/@name">
     ...
    </xsl:for-each-group>
    要在归类的同时做些简单运算,还有现成的函数可以用,例如 求和 sum, 计算条目个数 count ...
     
    问题来了,求和,计算条目个数都有现成函数,那求最大最小值,还有平均值这些类似的基本信息呢?
     
     
    能简则简,是懒人们的一贯追求。
     
    首先,用 avg(), min(), max() 直接试试。 报错,通不过。
     
    不死心,上 w3.org 查查,是不是拼写不对? avg 倒是找到了,min 和 max 没有踪影。
     
    还是不死心,上 w3schools 上看看 Functions Reference。 这里倒是声称 Functions on Sequences 包括 avg(), min() 还有 max(), 要求 XPath 2.0, XQuery 1.0 和 XSLT 2.0。 看来方法是有的,只是我的环境不支持。
     
     
    还是自己动手,丰衣足食吧。
     
    最简单的,先用 xsl:sort 排序,然后取首位。写起来挺简单,两行代码,可为了取个极值就对整个数列排序,是不是有点兴师动众?看看复杂度吧,不知道 xsl:sort 内部是怎么实现的,单从对排序算法的常识来看,搞不好有可能会是O(N2) 。现在数据量小还好说,以后用了分布式,操作类型再多些,弊端就露出来了。
     
    sort不行,换个XPath语句,<xsl:value-of select="$nodes[not($nodes &lt; .)]"/>,Select all nodes for which there is no node less than its value. 看看性能,又是O(N2) .
     
     
    老老实实,写个算法吧。想起了数据结构课程当中最简单排序算法,冒泡排序,去掉循环,用它来求极值不错,只要 n-1 次关键码比较, 容易实现,性能又好,就它了。吭哧吭哧,写完了,一试,还真不错。换几组数据再试试,不对啊,为什么有的时候正确有的时候就会错的莫名其妙?左看看,右看看,哦,每次求出的最大值都是以 9 打头的那个。原来默认的模式是字符比较。加上 number(..) ,一切OK啦!
     
    冒了一个泡泡