Skip to content

Instantly share code, notes, and snippets.

@CliffordAnderson
Last active December 3, 2016 22:08
Show Gist options
  • Save CliffordAnderson/5879867 to your computer and use it in GitHub Desktop.
Save CliffordAnderson/5879867 to your computer and use it in GitHub Desktop.
An attempt at the Luhn algorithm in XQuery
(: Signature of the fold function changed :)
xquery version "3.1";
(: Implements the Luhn Algorithm (http://en.wikipedia.org/wiki/Luhn_algorithm) in XQuery :)
declare function local:check-luhn($num as xs:integer) as xs:boolean
{
let $seq := fn:reverse(local:number-to-seq(($num)))
let $even-seq := $seq[position() mod 2 = 0]
let $odd-seq := $seq[position() mod 2 != 0]
let $sum-even := fn:fold-left($even-seq, 0, function($a, $b) { $a + (fn:sum(local:number-to-seq($b * 2)))})
let $sum-odd := fn:sum($odd-seq)
return (($sum-even + $sum-odd) mod 10) = 0
};
(: This function is adapted from a function by Nelson Wells :)
(: http://nelsonwells.net/2012/03/convert-an-integer-to-a-sequence-of-digits-in-xquery/ :)
declare function local:number-to-seq($num as xs:integer) as xs:integer*
{
if($num gt 9) then
(
local:number-to-seq(xs:integer(fn:floor($num div 10))),
xs:integer(fn:floor($num mod 10))
)
else
$num
};
(: Sample numbers from https://en.wikipedia.org/wiki/Luhn_algorithm :)
let $samples := (79927398710, 79927398711, 79927398712, 79927398713, 79927398714, 79927398715, 79927398716, 79927398717, 79927398718, 79927398719)
for $num in $samples
return local:check-luhn($num)
xquery version "3.0";
module namespace luhn = 'http://nullable.net/modules/luhn';
(: Implements the Luhn Algorithm (http://en.wikipedia.org/wiki/Luhn_algorithm) in XQuery :)
declare function luhn:check-luhn ($num as xs:integer) as xs:boolean
{
let $seq := fn:reverse(luhn:number-to-seq(($num)))
let $even-seq := $seq[position() mod 2 = 0]
let $odd-seq := $seq[position() mod 2 != 0]
let $sum-even := fn:fold-left(function($a, $b) { $a + (fn:sum(luhn:number-to-seq($b * 2)))}, 0, $even-seq)
let $sum-odd := fn:sum($odd-seq)
return (($sum-even + $sum-odd) mod 10) = 0
};
(: This function is adapted from a function by Nelson Wells :)
(: http://nelsonwells.net/2012/03/convert-an-integer-to-a-sequence-of-digits-in-xquery/ :)
declare function luhn:number-to-seq($num as xs:integer) as xs:integer*
{
if($num gt 9) then
(
luhn:number-to-seq(xs:integer(fn:floor($num div 10))),
xs:integer(fn:floor($num mod 10))
)
else
$num
};
@CliffordAnderson
Copy link
Author

I use the BaseX implementation of XQuery 3.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment