# Select elements in a list when the firsts two items are the same (no matter order) and its third element is lower

I'm trying to solve a heuristic search in Mathematica 9. I get a list of succesor nodes called open with two nodes and a heuristic value, e.g.,

open={{node1,node2,H1},...,{node2,node1,Hi},...,{noden,noden,Hn}}


I need to select only when the two first elements are the same (no matter order) but where the heuristic is lower. Following the code that I used for sort the elements by the first item

Sort[open, #1[[1]] < #2[[1]] &]


I try to select cases when the same first and second numbers and the heuristic value where lower:

Select[open, #1[[1]]==#2[[1]] &&  #1[[2]] == #2[[2]] && #1[[3]]< #2[[3]] &]


But, returns {}...

My list

open = {{1, 2, 3}, {2, 1, 5}, {1, 2, 2}, {3, 4, 5}, {4, 3, 2}};


Between {1, 2, 3}, {1, 2, 2}, and {2, 1, 5} then choose {1, 2, 2} that has the lower heuristic. And, between {3, 4, 5} and {4, 3, 2} then {4, 3, 2}...

{{1, 2, 2},{4, 3, 2}}


Thanks,

• Just as a remark: in your Select statement, you're using #2, but this won't do anything. The function in Select is a function of 1 argument only and the #2 slot will never be filled. Jul 29, 2017 at 19:09

You can try something like this:

First[Sort[#, #1[[3]] < #2[[3]] &]]&/@Gather[open, Complement[Most[#1], Most[#2]] === {}&]


{{1, 2, 2}, {4, 3, 2}}

this is a combination of two functions: First you gather the same edges and then you sort them according to their weight and take the first element (which has the lowest value.)

• Thanks, but can you explain me a little deeper what did you do? especially, the last part... Jun 5, 2013 at 14:22
• @user7892 If you mean the Complement[Most[#1], Most[#2]] === {} part, it's just a way using basic principles from set theory for gathering the same edges. Jun 5, 2013 at 15:22
• I did an effort to get it...yeah, in that part, you drop out the ones with same two firsts member. Thanks again, Jun 5, 2013 at 19:47

A combination of GatherBy[] and SortBy[] does the trick:

First[SortBy[#, Last]] & /@
GatherBy[{{1, 2, 3}, {2, 1, 5}, {1, 2, 2}, {3, 4, 5}, {4, 3, 2}}, Sort[Take[#, 2]] &]
{{1, 2, 2}, {4, 3, 2}}


In versions 10+, you can use MinimalBy combined with GroupBy:

open = {{1, 2, 3}, {2, 1, 5}, {1, 2, 2}, {3, 4, 5}, {4, 3, 2}};

Values @ GroupBy[open, Sort[#[[;; 2]]] &, First @ MinimalBy @ Last]


{{1, 2, 2}, {4, 3, 2}}

Or, MinimalBy combined with Merge

Values @ Merge[First @ MinimalBy @ Last][Sort[#[[;;2]]] -> # &/@ open]


{{1, 2, 2}, {4, 3, 2}}

Or, combined with GatherBy:

First @ MinimalBy[Last] /@ GatherBy[open, Sort[#[[;; 2]]] &]


{{1, 2, 2}, {4, 3, 2}}

For older versions, a combination of SplitBy and SortBy also works

First /@ SplitBy[SortBy[open, {Sort[#[[;;2]]]&, Last[#]&}], Sort[#[[;;2]]]&]


{{1, 2, 2}, {4, 3, 2}}

• Pardon me, but none of these seem better than J.M.'s GatherBy method. Would choose any of these in practice over it, and why? Jul 29, 2017 at 17:33