Mike J
Mike J

Reputation: 159

MarkLogic Xquery: How to sort string values in a for loop

I've got a sequence that needs to sort a list based off earliest year vs. latest year. Due to some unique values in the year element, it is making the sort a little more complicated. Is there any way to achieve the following?

let $dates := ('1982', '2019', '2095', 'pre-1982', 'post-2095')
return    
for $date in $dates
order by $date
return $date

the dates element text is usually the year in the data, but outlier cases have a pre- or post- attached. Any way to achieve this minimally?

Upvotes: 0

Views: 350

Answers (2)

line-o
line-o

Reputation: 1895

Just FYI: Definitely not minimal, but I wanted to know what fn:sort does when a sequence is returned. Turns out it does the right thing.

xquery version "3.1";

declare variable $local:ascending := 1;
declare variable $local:descending := -1;

declare function local:sort-prefixed-years ($y, $order) {
    if (fn:contains($y, "-")) 
    then (
        let $p := fn:tokenize($y, "-")
        let $m :=
            switch($p[1])
            case "pre" return -1 * $order
            case "post" return 1 * $order
            default return 0
        return (xs:integer($p[2]) * $order, $m)
    )
    else (xs:integer($y) * $order, 0)
};

declare function local:sort-prefixed-years-ascending ($prefixed-year) {
    local:sort-prefixed-years($prefixed-year, $local:ascending)
};

declare function local:sort-prefixed-years-descending ($prefixed-year) {
    local:sort-prefixed-years($prefixed-year, $local:descending)
};

let $dates := ('1982', '2019', '2095', 'pre-1982', 'post-2095')
return sort($dates, (), local:sort-prefixed-years-descending#1)

Upvotes: 0

Loren Cahlander
Loren Cahlander

Reputation: 1337

I am not sure if this is minimal, but it works:

let $dates := ('1982', '2019', '2095', 'pre-1982', 'post-2095')
return    
for $date in $dates
let $year := 
        if (fn:contains($date, "-")) 
        then fn:substring-after($date, "-") 
        else $date

let $prepost := 
        if (fn:starts-with($date, "pre")) 
        then -1 
        else if (fn:starts-with($date, "post")) 
        then 1
        else 0
order by $year, $prepost
return $date

Upvotes: 3

Related Questions