I'm trying to return subjects based on the relative position of their subjects in an ordered list.
A subject can be associated with multiple objects (via a single predicate) and all objects are in an ordered list. Given a reference object in this list I'd like to return the subjects in order of relative distance of their objects from the reference object.
:a : :x
:b : :v
:b : :z
:c : :v
:c : :y
:ls :list (:v :w :x :y :z)
Taking x as our starting object in the list, the code below returns
:a :x :0
:c :y :1
:b :v :2
:b :z :2
:c :v :2
Instead of returning all positions I would like only the objects relating to the subject's minimum object 'distance' to be returned (which may mean up to two objects per subject - both up and down the list). So I'd like to return
:a :x :0
:c :y :1
:b :v :2
:b :z :2
The code so far... (with a lot of help from Find lists containing ALL values in a set? and Is it possible to get the position of an element in an RDF Collection in SPARQL?)
SELECT ?s ?p (abs(?refPos-?pos) as ?dif)
WHERE {
:ls :list/rdf:rest*/rdf:first ?o .
?s : ?o .
{
SELECT ?o (count(?mid) as ?pos) ?refPos
WHERE {
[] :list/rdf:rest* ?mid . ?mid rdf:rest* ?node .
?node rdf:first ?o .
{
SELECT ?o (count(?mid2) as ?refPos)
WHERE {
[] :list/rdf:rest* ?mid2 . ?mid2 rdf:rest* ?node2 .
?node2 rdf:first :x .
}
}
}
GROUP BY ?o
}
}
GROUP BY ?s ?o
ORDER BY ?dif
I've been trying to get a minimum ?dif (difference/distance) by grouping by ?s but because I then have to apply this (something like ?dif = ?minDif) to the ?s ?o grouping from earlier I don't know how to go back and forward between these two groupings.
Thanks for any assistance you can provide