Re: [xsl] How to Do Random "Shuffle"?

Subject: Re: [xsl] How to Do Random "Shuffle"?
From: "Dimitre Novatchev dnovatchev@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 13 Sep 2014 16:40:04 -0000
This can be done even with XSLT 1.0:

http://fxsl.sourceforge.net/articles/Random/Casting%20the%20Dice%20with%20FXS
L-htm.htm

More specifically, use the FXSL 1 stylesheet module randomList.xsl

Here is an existing test (demo):

When this transformation (testRandomList.xsl):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:ext="http://exslt.org/common";
 xmlns:f="http://fxsl.sf.net/";
 xmlns:mySquare="f:mySquare"
 xmlns:myDouble="f:myDouble"
 exclude-result-prefixes="xsl f ext mySquare myDouble"
 >

  <xsl:import href="randomList.xsl"/>

  <xsl:output omit-xml-declaration="yes" indent="yes"/>
   <!-- This transformation must be applied to:
        numList.xml
     -->

  <mySquare:mySquare/>
  <myDouble:myDouble/>

  <xsl:template match="/">

    <xsl:variable name="vrtfRands">
      <xsl:call-template name="randomSequence">
        <xsl:with-param name="pLength" select="100"/>
      </xsl:call-template>
    </xsl:variable>

    Random Recursive Index (dScale (randomSequence 100)):

    <xsl:call-template name="_dScale">
      <xsl:with-param name="pRandSeq"
          select="ext:node-set($vrtfRands)/*"/>
    </xsl:call-template>

    Random Recursive Index 10:

    <xsl:variable name="vrtfRecIndex">
      <xsl:call-template name="_randomRecursiveIndex">
        <xsl:with-param name="pList"
        select="/*/*"/>
      </xsl:call-template>
    </xsl:variable>

    <xsl:variable name="vRecIndex"
              select="ext:node-set($vrtfRecIndex)/*"/>

    <xsl:for-each select="$vRecIndex">
      <xsl:copy-of select="."/>&#xA;
    </xsl:for-each>

    Randomized 10-elements list:
    <xsl:call-template name="_permutationFromRecursiveIndex">
      <xsl:with-param name="pList" select="/*/*"/>
      <xsl:with-param name="pRecIndex" select="$vRecIndex"/>
    </xsl:call-template>

    RandomizeList:
    <xsl:call-template name="randomizeList">
      <xsl:with-param name="pList" select="/*/*"/>
    </xsl:call-template>

    <xsl:variable name="vFunSquare"
         select="document('')/*/mySquare:*[1]"/>

    _mapFromRandIndex (^2) [1..10] seed:
    <xsl:call-template name="_mapFromRandIndex">
      <xsl:with-param name="pFun" select="$vFunSquare"/>
      <xsl:with-param name="pList" select="/*/*"/>
      <xsl:with-param name="pRecIndex" select="$vRecIndex"/>
    </xsl:call-template>

    <xsl:variable name="vFunDouble"
         select="document('')/*/myDouble:*[1]"/>

    randomMap (*2) [1..10] seed:
    <xsl:call-template name="randomMap">
      <xsl:with-param name="pFun" select="$vFunDouble"/>
      <xsl:with-param name="pList" select="/*/*"/>
    </xsl:call-template>

    randListIndex [1..10] seed:
    <xsl:call-template name="randListIndex">
      <xsl:with-param name="pList" select="/*/*"/>
    </xsl:call-template>

  </xsl:template>

  <xsl:template match="mySquare:*" mode="f:FXSL">
    <xsl:param name="arg1"/>

    <xsl:value-of select="$arg1 * $arg1"/>
  </xsl:template>
  <xsl:template match="myDouble:*" mode="f:FXSL">
    <xsl:param name="arg1"/>

    <xsl:value-of select="$arg1 + $arg1"/>
  </xsl:template>
</xsl:stylesheet>

is applied on this source XML document:

<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

the result is:



    Random Recursive Index (dScale (randomSequence 100)):

    <el>27</el>
<el>90</el>
<el>14</el>
<el>78</el>
<el>65</el>
<el>13</el>
<el>27</el>
<el>85</el>
<el>75</el>
<el>33</el>
<el>31</el>
<el>26</el>
<el>9</el>
<el>40</el>
<el>31</el>
<el>80</el>
<el>19</el>
<el>44</el>
<el>52</el>
<el>7</el>
<el>8</el>
<el>73</el>
<el>55</el>
<el>16</el>
<el>68</el>
<el>20</el>
<el>29</el>
<el>4</el>
<el>3</el>
<el>30</el>
<el>51</el>
<el>41</el>
<el>14</el>
<el>32</el>
<el>66</el>
<el>4</el>
<el>19</el>
<el>51</el>
<el>48</el>
<el>59</el>
<el>30</el>
<el>1</el>
<el>49</el>
<el>57</el>
<el>14</el>
<el>53</el>
<el>13</el>
<el>10</el>
<el>10</el>
<el>38</el>
<el>13</el>
<el>37</el>
<el>13</el>
<el>36</el>
<el>22</el>
<el>7</el>
<el>28</el>
<el>25</el>
<el>28</el>
<el>7</el>
<el>29</el>
<el>3</el>
<el>34</el>
<el>28</el>
<el>7</el>
<el>13</el>
<el>14</el>
<el>5</el>
<el>32</el>
<el>25</el>
<el>25</el>
<el>24</el>
<el>8</el>
<el>26</el>
<el>23</el>
<el>14</el>
<el>11</el>
<el>18</el>
<el>15</el>
<el>6</el>
<el>5</el>
<el>6</el>
<el>9</el>
<el>4</el>
<el>8</el>
<el>14</el>
<el>12</el>
<el>12</el>
<el>5</el>
<el>2</el>
<el>5</el>
<el>1</el>
<el>4</el>
<el>1</el>
<el>4</el>
<el>4</el>
<el>1</el>
<el>2</el>
<el>1</el>
<el>1</el>

    Random Recursive Index 10:

    <el>3</el>
<el>9</el>
<el>2</el>
<el>6</el>
<el>5</el>
<el>1</el>
<el>2</el>
<el>3</el>
<el>2</el>
<el>1</el>

    Randomized 10-elements list:
    <el>03</el>
<el>10</el>
<el>02</el>
<el>08</el>
<el>07</el>
<el>01</el>
<el>05</el>
<el>09</el>
<el>06</el>
<el>04</el>

    RandomizeList:
    <el>03</el>
<el>10</el>
<el>02</el>
<el>08</el>
<el>07</el>
<el>01</el>
<el>05</el>
<el>09</el>
<el>06</el>
<el>04</el>

    _mapFromRandIndex (^2) [1..10] seed:
    <el>9</el>
<el>100</el>
<el>4</el>
<el>64</el>
<el>49</el>
<el>1</el>
<el>25</el>
<el>81</el>
<el>36</el>
<el>16</el>

    randomMap (*2) [1..10] seed:
    <el>6</el>
<el>20</el>
<el>4</el>
<el>16</el>
<el>14</el>
<el>2</el>
<el>10</el>
<el>18</el>
<el>12</el>
<el>8</el>

    randListIndex [1..10] seed:
    <el>3</el>
<el>10</el>
<el>2</el>
<el>8</el>
<el>7</el>
<el>1</el>
<el>5</el>
<el>9</el>
<el>6</el>
<el>4</el>

The last result gives us a random index of the integers in [1, 10]

These indexes can be used to select in a random order 10 nodes.

In XSLT 2 one can use the standard XPath function current-time() for
the creation of the seed:
http://www.w3.org/TR/xpath-functions/#func-current-time

Cheers,
Dimitre



On Sat, Sep 13, 2014 at 7:29 AM, Eliot Kimber ekimber@xxxxxxxxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
> Using XSLT 2 I need to implement rendering of "match table" questions
> where you have two sets of items, the match item and the thing it matches
> to. I want to present this as a literal table, where the first column is
> the match-from items in source order and the second column is the match-to
> items, in random order.
>
> I think this is best characterized as a "shuffle" problem, where you want
> to reorder a list randomly but all items in the list must be accounted
> for.
>
> I can think of a recursive algorithm: given a list, generate a random
> integer between 1 and the list length, select that item and add it to the
> result list, then call this function on the original list minus the node
> you just selected.
>
> Is there an easier or more efficient way to do it?
>
> Thanks,
>
> Eliot
> bbbbb
> Eliot Kimber, Owner
> Contrext, LLC
> http://contrext.com

Current Thread