I'm trying to pick 5 nodes at random. I've tried a couple of ways of doing this (e.g the two mentioned here: http://our.umbraco.org/forum/developers/xslt/6605-Best-Way-To-Get-Random-Nodes-From-Specific-Node) but because the original data set is so large these are either unreliable or very poorly performing. So before I create my own XSLT extension I thought I'd try the magical uComponents.
I notice there are some extension methods for generating random numbers in uComponents, but I'm ideally looking for something that will return 5 random numbers within a range. There's a method called 'GetRandomNumbers' but it only takes a single integer as an input parameter and I think it only outputs a range between 1 and 10.
There's also a GetRandomNumber method which takes a maximum and optional minimum parameter, so this might be a reasonable solution - just to call this method 5 times.
Has anyone come across any other ways of doing this, or is there anything else in uComponents that could achieve the same thing?
Yeah, just checked, the GetRandomNumbers function takes the input value as the max number, and the start number defaults to 1 ... I can add an overload to make it accept a start and end value, and pick random numbers within the range?
There is one called "RandomSort(XPathNavigator node, int count)"in the XML extensions. You can pass it a nodeset (from XSLT) and a count, then it will sort the nodes in random order and return the nodeset limited by the count.
(This isn't on the documentation page ... I do need to give the doco some TLC) :-)
Thanks Lee. Ordinarily that would do just the job, but I think the issue with this particular situation is that the data-set is large (3000+ nodes, 150 properties per node) so I fear that using the RandomSort method or the RandomNode method in the 'xml' extension may be pretty slow? You can probably advise whether it'd be any quicker, but the route I was going to take was to generate a nodeset of just node ids from the original data-set, count these, generate 5 random numbers via an XSLT extension within the range 1 to total-count, then basically grab the node ids from the 5 random positions and run a 'GetXmlNodeById' on those. This way the only time the full 150-property nodes are being processed is at the very end, just for the 5 selected nodes. I thought this may be better performing than putting everything into a node-set and trying to process that? Certainly having tried to do a dynamic sort on the full nodeset through just XSLT is really slow - maybe the extension handles it differently?
It does make sense, and you're right, the RandomSort/RandomNode would most likely be slower performance.
If you can build up a CSV of nodeIds, then I'd be tempted to try the following XSLT extension:
namespace Our.Umbraco
{
using System;
using System.Linq;
[umbraco.XsltExtension("our.umbraco")]
public class XsltExtensions
{
public static string GetRandomItemsFromCsv(string csv, int count)
{
// if empty, return empty
if (string.IsNullOrWhiteSpace(csv))
return string.Empty;
// split CSV, load into array
var list = csv.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
// randomly sort the order of the list (based on GUIDs)
var items = list.OrderBy(s => Guid.NewGuid()).ToList();
// if the number of items is larger than the count...
if (items.Count >= count)
{
// ... then take the first [x] items
items = items.Take(count).ToList();
}
// rebuild the CSV
return string.Join(",", items.ToArray());
}
}
}
Many weeks later I'm revisiting this (the original thread was for a personal project which is still on the back-burner) on a 4.9.0 installation. Did this make it into the most recent version of uComponents, before I create the XSLT extension?
Get x random numbers within a range
Hi,
I'm trying to pick 5 nodes at random. I've tried a couple of ways of doing this (e.g the two mentioned here: http://our.umbraco.org/forum/developers/xslt/6605-Best-Way-To-Get-Random-Nodes-From-Specific-Node) but because the original data set is so large these are either unreliable or very poorly performing. So before I create my own XSLT extension I thought I'd try the magical uComponents.
I notice there are some extension methods for generating random numbers in uComponents, but I'm ideally looking for something that will return 5 random numbers within a range. There's a method called 'GetRandomNumbers' but it only takes a single integer as an input parameter and I think it only outputs a range between 1 and 10.
There's also a GetRandomNumber method which takes a maximum and optional minimum parameter, so this might be a reasonable solution - just to call this method 5 times.
Has anyone come across any other ways of doing this, or is there anything else in uComponents that could achieve the same thing?
Thanks!
Hi Dan,
Yeah, just checked, the GetRandomNumbers function takes the input value as the max number, and the start number defaults to 1 ... I can add an overload to make it accept a start and end value, and pick random numbers within the range?
Would that work for you?
Cheers, Lee.
There is one called "RandomSort(XPathNavigator node, int count)"in the XML extensions. You can pass it a nodeset (from XSLT) and a count, then it will sort the nodes in random order and return the nodeset limited by the count.
(This isn't on the documentation page ... I do need to give the doco some TLC) :-)
Cheers, Lee
Thanks Lee. Ordinarily that would do just the job, but I think the issue with this particular situation is that the data-set is large (3000+ nodes, 150 properties per node) so I fear that using the RandomSort method or the RandomNode method in the 'xml' extension may be pretty slow? You can probably advise whether it'd be any quicker, but the route I was going to take was to generate a nodeset of just node ids from the original data-set, count these, generate 5 random numbers via an XSLT extension within the range 1 to total-count, then basically grab the node ids from the 5 random positions and run a 'GetXmlNodeById' on those. This way the only time the full 150-property nodes are being processed is at the very end, just for the 5 selected nodes. I thought this may be better performing than putting everything into a node-set and trying to process that? Certainly having tried to do a dynamic sort on the full nodeset through just XSLT is really slow - maybe the extension handles it differently?
Does this make any sense at all? ;)
It does make sense, and you're right, the RandomSort/RandomNode would most likely be slower performance.
If you can build up a CSV of nodeIds, then I'd be tempted to try the following XSLT extension:
I haven't tested this, so might need some tinkering... let me know how it works out - will probably add it to next uComponents release! ;-)
Cheers, Lee.
Wow, thanks! Will let you know how it goes...
Hi Lee,
Many weeks later I'm revisiting this (the original thread was for a personal project which is still on the back-burner) on a 4.9.0 installation. Did this make it into the most recent version of uComponents, before I create the XSLT extension?
Thanks
Hi Dan,
Just checked latest uComponents (v5.0) ... and no, sorry, it's not in there. (Only because I'd forgot about it)
I'll add it in for v5.1 (due for release soon). In the meantime, might be worth using it as a custom extension.
Cheers, Lee.
No, probs, just thought it was worth checking. Thanks.
Just added it in for v5.1 ... thought best to do it now, otherwise I'd forget (again!) ;-)
is working on a reply...