Drop list if element found in nested list in kotlin - kotlin
Hey I have a huge list coming from server. I am adding some data at top of list. I want to remove data from the list. I have nested list in which I need to find the element in nested list.
fun categoriesList() = listOf(
Categories("21", "physical", listOf(SubTopic("1", "abc"), SubTopic("2", "bjhef"))),
Categories("2211", "mind", listOf(SubTopic("1", "abc"), SubTopic("2", "bjhef"))),
Categories("22131", "motorized", listOf(SubTopic("1", "abc"), SubTopic("2", "bjhef"))),
Categories("2134124", "coordination", listOf(SubTopic("1", "abc"), SubTopic("2", "bjhef"))),
Categories("211243", "animal-supported", listOf(SubTopic("1", "abc"), SubTopic("2", "bjhef"))),
)
Categories.kt
data class Categories(
val id: String? = null, val title: String? = null, val subTopic: List<SubTopic>? = null
)
SubTopic.kt
data class SubTopic(
val id: String? = null, val title: String? = null, var priceId: String? = null
)
main.kt
var categoryList: List<Categories>? = null
fun main() {
categoryList = categoriesList()
categoryList?.add(0, Categories("0", "physical-ktm", listOf(SubTopic("1", "vivek"))))
}
So I want to find title = "Vivek" if that found I want to drop my whole list index 0 element data. Important I only need to check element at index 0. I don't want to iterate whole list. If found the data in index 0 drop it otherwise leave it the iteration. So what is efficient way of doing this in kotlin idiomatic way. Can someone guide me. Thanks
UPDATE
categoryList?.forEachIndexed { index, data->
println("$index index -> $data")
}
console
0 index -> Categories(id=0, title=physical-ktm, subTopic=[SubTopic(id=1, title=vivek, priceId=null)])
1 index -> Categories(id=21, title=physical, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
2 index -> Categories(id=2211, title=mind, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
3 index -> Categories(id=22131, title=motorized, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
4 index -> Categories(id=2134124, title=coordination, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
5 index -> Categories(id=211243, title=animal-supported, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
I only want to search in 0 index of Categories and if title = "vivek" is found in subTopic then I want to drop 0 index from Categories and stop iteration. If data is not found at all in subTopic then I don't won't to iterate whole list of Categories.
After #Tenfour04 suggestion I added this code
var categoryList: MutableList<Categories>? = null
fun main() {
categoryList = categoriesList().toMutableList()
categoryList?.add(0, Categories("0", "physical-ktm", listOf(SubTopic("1", "vivek"))))
println("After Add")
categoryList?.forEachIndexed { index, categories ->
println("$index index -> $categories")
}
val matchingIndex = categoryList?.indexOfFirst { it.subTopic?.first()?.title == "vivek" }
if (matchingIndex != null && matchingIndex >= 0) {
categoryList = categoryList?.mapIndexed { index, it ->
if (index == matchingIndex)
it.copy(subTopic = it.subTopic?.drop(1))
else
it
} as MutableList<Categories>?
}
println("After operation")
categoryList?.forEachIndexed { index, categories ->
println("$index index -> $categories")
}
}
Actual Output
After Add
0 index -> Categories(id=0, title=physical-ktm, subTopic=[SubTopic(id=1, title=vivek, priceId=null)])
1 index -> Categories(id=21, title=physical, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
2 index -> Categories(id=2211, title=mind, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
3 index -> Categories(id=22131, title=motorized, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
4 index -> Categories(id=2134124, title=coordination, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
5 index -> Categories(id=211243, title=animal-supported, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
After operation
0 index -> Categories(id=0, title=physical-ktm, subTopic=[])
1 index -> Categories(id=21, title=physical, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
2 index -> Categories(id=2211, title=mind, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
3 index -> Categories(id=22131, title=motorized, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
4 index -> Categories(id=2134124, title=coordination, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
5 index -> Categories(id=211243, title=animal-supported, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
Expect Output
After Add
0 index -> Categories(id=0, title=physical-ktm, subTopic=[SubTopic(id=1, title=vivek, priceId=null)])
1 index -> Categories(id=21, title=physical, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
2 index -> Categories(id=2211, title=mind, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
3 index -> Categories(id=22131, title=motorized, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
4 index -> Categories(id=2134124, title=coordination, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
5 index -> Categories(id=211243, title=animal-supported, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
After operation
0 index -> Categories(id=21, title=physical, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
1 index -> Categories(id=2211, title=mind, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
2 index -> Categories(id=22131, title=motorized, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
3 index -> Categories(id=2134124, title=coordination, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
4 index -> Categories(id=211243, title=animal-supported, subTopic=[SubTopic(id=1, title=abc, priceId=null), SubTopic(id=2, title=bjhef, priceId=null)])
I want to remove whole Categoriesobject which is present at index 0.
My understood description of the task: Find the first (and only first) Categories in categoriesList that has a subList whose first SubTopic has a title of "vivek". If it is found, set categoriesList to a new List where the Categories where it was found has been replaced with a new Categories instance whose subList has the matched first SubTopic removed.
If prioritizing clarity, I would use map even though it will copy the list regardless of whether any Categories are modified. And I'd use a Boolean variable to determine whether the search must continue.
var itemFound = false
categoriesList = categoriesList.map {
if (!itemFound && it.subTopic?.first()?.title == "vivek") {
itemFound = true
it.copy(subTopic = it.subTopic?.drop(1))
} else {
it
}
}
If prioritizing performance, I would search using indexOf so I would only create the new list if necessary. But really, if performance is truly this critical we really should be using mutable collections and data classes. That might not be possible if doing list comparisons, of course.
val matchingIndex = categories.indexOfFirst { it.subTopic?.first()?.title == "vivek"}
if (matchingIndex >= 0) {
categoriesList = categoriesList.mapIndexed { index, it ->
if (index == matchingIndex)
it.copy(subTopic = it.subTopic?.drop(1))
else
it
}
}
Edit: based on your new comment, I think this is what you are asking for now. Quite a bit simpler.
if(categoriesList.first().subTopics.orEmpty().any { it.title == “vivek” }) {
categoriesList = categoriesList.drop(1)
}
So if I understand the question correctly, you want to eliminate the first – and only the first – subtopic for each category in categoriesList if its title is "Vivek":
data class SubTopic(
val id: String? = null,
val title: String? = null,
var priceId: String? = null
)
data class Categories(
val id: String? = null,
val title: String? = null,
val subTopic: List<SubTopic>? = null
)
val categoriesList = listOf(
Categories("21", "physical", listOf(SubTopic("1", "abc"), SubTopic("2", "Vivek"))),
Categories("2211", "mind", listOf(SubTopic("1", "Vivek"), SubTopic("2", "bjhef"))),
Categories("22131", "motorized", listOf(SubTopic("1", "abc"), SubTopic("2", "bjhef"))),
Categories("2134124", "coordination", listOf(SubTopic("1", "Vivek"), SubTopic("2", "Vivek"))),
Categories("211243", "animal-supported", listOf(SubTopic("1", "abc"), SubTopic("2", "bjhef"))),
)
var categoryList = categoriesList
.map {
it.copy(subTopic = it.subTopic
?.filterIndexed { index, subTopic -> (index == 0 && subTopic.title != "Vivek") || index > 0 }
)
}
categoryList.forEach(::println)
Related
Sequence Http.get in Elm
Below I have a button that attempts to load remote content ... import Post exposing (Post) import Html exposing (..) import Html.Events exposing (..) import Http import Json.Decode as Decode type alias Model = { posts : List Post } type Msg = Search String | PostsReceived (Result Http.Error (List Post)) update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of Search s -> let cmd = (Decode.list Post.decode) |> Http.get ("/posts?author=" ++ s) |> Http.send PostsReceived in ( model, cmd ) PostsReceived (Ok posts) -> { model | posts = posts } ! [] PostsReceived (Err error) -> ( model, Cmd.none ) view : Model -> Html Msg view model = button [ onClick (Search "amelia") ] [ text "Read posts by Amelia" ] This is a valid Elm program, only there's one little problem: The API doesn't allow me to search by string. This is not allowed /posts?author=amelia => Malformed Request Error However, this is allowed /posts?author=2 => [ {...}, {...}, ... ] So I must first fetch an author to get his/her id, and then I can fetch posts using the author's id... /author?name=amelia => { id: 2, name: "amelia", ... } /posts?author=2 How can I sequence one request after the next? Ideally I'd like to cache the authors somewhere in the model so we're only requesting ones that we haven't seen before.
You can use Task.andThen to chain two tasks together. Assuming that the /posts response includes the author ID, you can then add that author ID into you model when you handle the response. Search s -> let getAuthor = Author.decode |> Http.get ("/author?name=" ++ s) |> Http.toTask getPosts author = (Decode.list Post.decode) |> Http.get ("/posts?author=" ++ author.id) |> Http.toTask cmd = getAuthor |> Task.andThen getPosts |> Task.attempt PostsReceived in ( model, cmd ) I've got this compiling at https://ellie-app.com/DBJc6Kn3G6a1 if that helps
You can chain together tasks using Task.andThen. You'll first have to convert the web requests to tasks using Http.toTask: postsByAuthorName : String -> Cmd Msg postsByAuthorName name = Http.get ("/author?name=" ++ name) (Decode.field "id" Decode.int) |> Http.toTask |> Task.andThen (\id -> Http.get ("/posts?author=" ++ toString id) (Decode.list decodePost) |> Http.toTask) |> Task.attempt PostsReceived
A a dictionary and a couple more Msg options should do it. You'll have to write the decoder for the Author response, but other than that this should work type alias Model = { posts : List Post , authors : Dict String Int } type Msg = Search String | SearchAuthor String | AuthorReceived (Result Http.Error Int String) | PostsReceived (Result Http.Error (List Post)) update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of Search author -> case (Dict.get author model.authors) of Nothing -> let cmd = (Decode.list Post.decode) |> Http.get ("/author?name=" ++ author) |> Http.send AuthorReceived in (model,cmd) Just num -> let cmd = (Decode.list Author.decode) |> Http.get ("/posts?author=" ++ num) |> Http.send PostsReceived in ( model, cmd ) AuthorReceived (Ok number name) -> let updatedAuthors = Dict.inster name number model.authors cmd = (Decode.list Post.decode) |> Http.get ("/posts?author=" ++ number) |> Http.send PostsReceived in {model | authors = updatedAuthors } ! [cmd] AuthorReceived (Err error) -> (mode, Cmd.none ) PostsReceived (Ok posts) -> { model | posts = posts } ! [] PostsReceived (Err error) -> ( model, Cmd.none ) view : Model -> Html Msg view model = button [ onClick (Search "amelia") ] [ text "Read posts by Amelia" ]
Uncaught TypeError: Cannot read property 'week' of undefined
I'm getting an uncaught typeerror in elm and don't know why. I'm decoding a json string from an api; the api is giving a list of rostars and each rostar has either a planningId or a flexplanningId. I'd like to map over the list and give each planning a unique id based either on the planningId or the flexplanningId, depending on which it has. Here's the code: The record definition and the decoders: type alias Rostar = { employee : Employee } type alias Employee = { week : Week , name : String , id : Int , contractHours : Float } type alias Week = { monday : List Planning , tuesday : List Planning , wednesday : List Planning , thursday : List Planning , friday : List Planning , saturday : List Planning , sunday : List Planning } type alias Planning = { time : String , planningId : Maybe Int , groupId : Int , groupName : String , flex : Bool , employeeTimeslotId : Maybe Int , flexplanningId : Maybe Int , employeeId : Maybe Int , id : Maybe Int } responseDecoder : Decoder (List Rostar) responseDecoder = list rostarDecoder rostarDecoder : Decoder Rostar rostarDecoder = decode Rostar |> required "employee" employeeDecoder employeeDecoder : Decoder Employee employeeDecoder = decode Employee |> required "rostar" weekDecoder |> required "name" string |> required "id" int |> required "contract_hours" float weekDecoder : Decoder Week weekDecoder = decode Week |> required "monday" (list planningDecoder) |> required "tuesday" (list planningDecoder) |> required "wednesday" (list planningDecoder) |> required "thursday" (list planningDecoder) |> required "friday" (list planningDecoder) |> required "saturday" (list planningDecoder) |> required "sunday" (list planningDecoder) planningDecoder : Decoder Planning planningDecoder = decode Planning |> required "time" string |> optional "planning_id" (nullable int) Nothing |> required "group_id" int |> required "group_name" string |> required "flex" bool |> optional "employee_timeslot_id" (nullable int) Nothing |> optional "flexplanning_id" (nullable int) Nothing |> required "employee_id" (nullable int) |> hardcoded Nothing The mapping: update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of HandleFeedResponse response -> let assignPlanningId : Planning -> Planning assignPlanningId planning = case planning.planningId of Just id -> { planning | id = Just (id + 10000000) } Nothing -> case planning.flexplanningId of Just id -> { planning | id = Just (id + 90000000) } Nothing -> { planning | id = Nothing } planningWithId : List Planning -> List Planning planningWithId day = List.map assignPlanningId day mapWeek : Week -> Week mapWeek week = { week | monday = planningWithId week.monday , tuesday = planningWithId week.tuesday , wednesday = planningWithId week.wednesday , thursday = planningWithId week.thursday , friday = planningWithId week.friday , saturday = planningWithId week.saturday , sunday = planningWithId week.sunday } updateResponse : List Rostar updateResponse = List.map (\r -> let employee = { employee | week = mapWeek employee.week } in { r | employee = employee } ) response check = Debug.log "updatedResponse" updateResponse in { model | rostar = updateResponse } ! [] Here's the error I'm getting: Uncaught TypeError: Cannot read property 'week' of undefined Blockquote Thanks for the help!
I think your problem is caused by the let binding of employee in the updateResponse mapping function. The label employee already exists, so this line is causing a recursive definition. let employee = { employee | week = mapWeek employee.week } In Elm 0.18, this is a compile error and gives you a detailed error message rather than leaving the possibility for a runtime error: Detected errors in 1 module. -- BAD RECURSION ------------------------------------------------------ Main.elm employee is defined directly in terms of itself, causing an infinite loop. 132|> employee = 133| { employee | week = mapWeek employee.week } Maybe you are trying to mutate a variable? Elm does not have mutation, so when I see employee defined in terms of employee, I treat it as a recursive definition. Try giving the new value a new name! Maybe you DO want a recursive value? To define employee we need to know what employee is, so let’s expand it. Wait, but now we need to know what employee is, so let’s expand it... This will keep going infinitely! To really learn what is going on and how to fix it, check out: https://github.com/elm-lang/elm-compiler/blob/0.18.0/hints/bad-recursion.md Prior to 0.18, I would see these types of odd "undefined" runtime errors when accidentally performing some kind of unintended recursion. In 0.18, they've added compiler checks for some of the most basic types of problems.
This may not the source of your error, but your employee-decoder says it needs a rostar variable, which contains a week. Is this correct? Or should it be called week? Here is the code snippet: employeeDecoder : Decoder Employee employeeDecoder = decode Employee -- |> required "rostar" weekDecoder -- is this correct? |> required "week" weekDecoder -- what I would have expected |> required "name" string |> required "id" int |> required "contract_hours" float
Elm 0.17: Task.perform and Maybe
I'm hoping someone could help me with Task.perform as I don't really understand how to handle a Maybe response - and the docs aren't making things clearer for me. In my model I have results which Maybe a list of items or Nothing. -- model type alias Item = { name : String} type alias Model = { results : Maybe (List Item) } model = { results = Nothing } I perform a Task and decode it like so: -- Task fetch : String -> Cmd Msg fetch query = let url = "https://some_url" ++ query in Task.perform FetchFail FetchSuccess (Http.get decode url) -- decoder decoder: Json.Decoder (List Item) decoder = Json.at ["data"] (Json.list nestedListDecoder) -- nestedListDecoder nestedListDecoder : Json.Decoder Item nestedListDecoder = Json.object1 Item ("name" := Json.string) I then handle the response in update: -- update type Msg = FetchSuccess (Maybe (List Item)) | FetchFail Http.Error update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of FetchSuccess results -> case results of Nothing -> ( { model | results = Nothing}, Cmd.none) Just res -> ( { model | results = res }, Cmd.none) FetchFail err -> -- ... handle error And cater for the Maybe in the view: -- view result : Item -> Html Msg result item = li [] [ text item.name ] view : Model -> Html Msg view model = ul [ ] (List.map result (Maybe.withDefault [] model.results)) I am getting this error when dealing with Maybe of results. 198| Task.perform FetchFail FetchSuccess (Http.get repos url) ^^^^^^^^^^^^^^^^^^ Function `perform` is expecting the 3rd argument to be: Task Http.Error (Maybe (List Repo)) But it is: Task Http.Error (List Repo) Can anyone advise where else I need to cater for the Maybe ?
A simple tweak to your decoder should fix it. The decoder just needs to use Json.Decode.maybe: decoder: Json.Decoder (Maybe (List Item)) decoder = Json.maybe <| Json.at ["data"] (Json.list nestedListDecoder)
Dynamic SQL Parameters with Anorm and Scala Play Framework
Is it possible to dynamically create a list for anorm's "on" method? I have a form with optional inputs and currently I check each Option and create a list with the defined Options and am trying to pass this through to anorm. Currently I get this compilation error type mismatch; found : List[java.io.Serializable] required: (Any, anorm.ParameterValue[_]) I'm not sure how I would go about creating this list. Current code : val onList = List( 'school_id = input.school, if(input.rooms isDefined) ('rooms -> input.rooms) else "None" , if(input.bathrooms isDefined) ('bathrooms -> input.bathrooms) else "None" , if(input.houseType isDefined) ('houseType -> input.houseType) else "None" , if(input.priceLow isDefined) ('priceLow -> input.priceLow) else "None" , if(input.priceHigh isDefined) ('priceHigh -> input.priceHigh) else "None" , if(input.utilities isDefined) ('utilities -> input.utilities) else "None" ).filter(_!="None") SQL("SELECT * FROM Houses WHERE " + whereString).on(onList).as(sqlToHouse *) I've tried doing this because initially I thought it would be the same as .on('rooms -> input.rooms, 'bathroom -> input.bathrooms... etc) EDIT: Code is now: val onList = Seq( ('school_id -> input.school), if(input.rooms isDefined) ('rooms -> input.rooms.get) else None , if(input.bathrooms isDefined) ('bathrooms -> input.bathrooms.get) else None , if(input.houseType isDefined) ('houseType -> input.houseType.get) else None , if(input.priceLow isDefined) ('priceLow -> input.priceLow.get) else None , if(input.priceHigh isDefined) ('priceHigh -> input.priceHigh.get) else None , if(input.utilities isDefined) ('utilities -> input.utilities.get) else None ).filter(_!=None).asInstanceOf[Seq[(Any,anorm.ParameterValue[_])]] using SQL command: SQL("SELECT * FROM Houses WHERE " + whereString).on(onList:_*).as(sqlToHouse *) Now getting the exception [ClassCastException: java.lang.Integer cannot be cast to anorm.ParameterValue]
The important thing is that you have to create values of type ParameterValue. This is normally done using the toParameterValue() function. One way would be to create a sequence of Options that you flatten: val onList = Seq( Some('school_id -> input.school), input.rooms.map('rooms -> _), input.bathrooms.map('bathrooms -> _) ).flatten This sequence can then be mapped to correct values: SQL( "SELECT * FROM Houses WHERE " + whereString ).on( onList.map(v => v._1 -> toParameterValue(v._2)): _* ) This can be simplified like this: val onList = Seq( Some('school_id -> input.school), input.rooms.map('rooms -> _), input.bathrooms.map('bathrooms -> _) ).flatMap(_.map(v => v._1 -> toParameterValue(v._2))) SQL( "SELECT * FROM Houses WHERE " + whereString ).on( onList: _* ) Or maybe the simplest solution would be this: val onList = Seq( Some('school_id -> toParameterValue(input.school)), input.rooms.map('rooms -> toParameterValue(_)), input.bathrooms.map('bathrooms -> toParameterValue(_)) ).flatten SQL( "SELECT * FROM Houses WHERE " + whereString ).on( onList: _* )
So I ended up just calling on multiple times. var query = SQL("SELECT * FROM Houses WHERE " + whereString).on('school_id -> input.school) if(input.rooms isDefined) query= query.on('rooms -> input.rooms.get) if(input.bathrooms isDefined) query= query.on('bathrooms -> input.bathrooms.get) if(input.houseType isDefined) query= query.on('houseType -> input.houseType.get) if(input.priceLow isDefined) query= query.on('priceLow -> input.priceLow.get) if(input.priceHigh isDefined) query= query.on('priceHigh -> input.priceHigh.get) if(input.utilities isDefined) query= query.on('utilities -> input.utilities.get) query.as(sqlToHouse *)
You can have a look at multivalue parameter is next Anorm (coming Play 2.3/master).
Filtering SPARQL Results
I have following example triples r1 -> property -> resourceA r1 -> property -> resourceB r1 -> property -> resourceC resourceA -> name -> word1 resourceB -> name -> word2 resourceC -> name -> word4 r2 -> property -> resourceD r2 -> property -> resourceE r2 -> property -> resourceF resourceD -> name -> word1 resourceE -> name -> word2 resourceF -> name -> word3 r3 -> property -> resourceG r3 -> property -> resourceH r3 -> property -> resourceI resourceG -> name -> word5 resourceH -> name -> word6 resourceI -> name -> word7 As parameter i use word1 and word2. I want to get all words incl. word1 and word2, which occurrence with the word1 and word2 together. The result from this example must be: word1 word2 word3 word4 I have really no idea, how to make this :(
Assuming the predicate name is the same for all words and there are no other triples with the name predicate: SELECT DISTINCT ?w { ?s <name> ?w } ORDER BY ?w Edited after the question was edited: SELECT DISTINCT ?w { # select each word only once # match three properties under the same resource ?r <property> ?p1, ?p2, ?p3. # two of the properties must have names "word1" and "word2" ?p1 <name> "word1" . ?p2 <name> "word2" . # third property name may be anything, including "word1" and "word2" ?p3 <name> ?w . } ORDER BY ?w # return words in sorted order