4
$\begingroup$

I have a list like:

   {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, 
    {{4, 18}, 1}, {{4, 14}, 3},  {4,15},      {{4, 16}, 2},{4,18}}

Now I want to filter this list. First I want to delete lists that have the form: {a,b} like {4,15} and {4,18}. So what remains is:

 {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, 
  {{4, 18}, 1}, {{4, 14} ,3}, {{4, 16}, 2}}

And now I want only the lists which are a minimum: For example now you have a list with:

{{4, 14}, 1} and {{4, 14}, 3}
{{4, 16}, 1} and {{4, 16}, 2}

I want that only {{4, 14}, 1} and {{4, 16}, 1} remain (minimum of the third number).

Finally remains:

{{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}

How can I easily do this??

$\endgroup$
1
  • 1
    $\begingroup$ Glenn, as you can see from the answers below there is ambiguity in your question. Do you want to return only elements of the form {{_, _}, min} where min is the global minimum across all lists, or rather elements where min is the smallest value within the set that share a common first part (e.g. {4, 14})? $\endgroup$
    – Mr.Wizard
    Commented Dec 16, 2012 at 23:08

9 Answers 9

6
$\begingroup$

Yet another way using Select and GatherBy:

list = {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 
    1}, {{4, 18}, 1}, {{4, 14}, 3}, {4, 15}, {{4, 16}, 2}, {4, 18}};
x1 = Select[list, Length[#[[1]]] == 2 &];
x2 = GatherBy[x1, First];
(Sort[#] & /@ x2)[[All, 1]]

{{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}}

$\endgroup$
2
  • $\begingroup$ You could use SortBy[#,Last] instead of Sort[#, #1[[2]] < #2[[2]] &] . Or, for this problem, just Sort since the first elements are all the same $\endgroup$ Commented Dec 16, 2012 at 17:31
  • $\begingroup$ @SimonWoods You're right, updated. $\endgroup$
    – VLC
    Commented Dec 16, 2012 at 17:58
5
$\begingroup$

another way

list = DeleteCases[list, {x_Integer, y_Integer}];
min = Min[list[[All, 2]]];
Extract[list, Position[list[[All, 2]], min] ]

Mathematica graphics

$\endgroup$
1
  • $\begingroup$ You're assuming the minimum (third number) is just going to be one number, in this case 1, but it seems the different lists could have various minimum numbers. $\endgroup$ Commented Dec 16, 2012 at 16:38
4
$\begingroup$
lst = {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1},
       {{4, 17}, 1}, {{4, 18}, 1}, {{4, 14}, 3}, {4, 15}, {{4, 16}, 2}, {4, 18}}

First /@ Sort /@ GatherBy[Cases[lst, {_List, _}], First]
{{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}}

Or with ~infix~:

First /@ Sort /@ lst ~Cases~ {_List, _} ~GatherBy~ First
$\endgroup$
2
$\begingroup$

Here's a fairly simple way of doing it:-

x = {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1},
     {{4, 18}, 1}, {{4, 14}, 3}, {4, 15}, {{4, 16}, 2}, {4, 18}};
x2 = Replace[x, {a_Integer, b_Integer} -> Null, {1}];
x3 = DeleteCases[x2, Null];
types = Union[x3[[All, 1]]];
First[Sort[Cases[x3, {#, _}]]] & /@ types

{{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}}

$\endgroup$
2
$\begingroup$

An approach based on Cases:

lst = {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1},
   {{4, 17}, 1}, {{4, 18}, 1}, {{4, 14}, 3}, {4, 15}, {{4, 16}, 2}, {4, 18}}

Cases[list, {{_, _}, Min[list /. {{_, _}, x_} -> x]}]

{{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}}

$\endgroup$
2
$\begingroup$

With

x = {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, 
  {{4, 18}, 1}, {{4, 14}, 3}, {4, 15}, {{4, 16}, 2}, {4, 18}};
x2 = {{{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}, 
  {{4, 14}, 3}, {4, 15}, {{4, 16}, 2}, {4, 18}, {{4, 14}, 2}};

you can also use

 Union[Cases[x, {{ _, _ }, _}], SameTest -> (First@#1 == First@#2 &)]

or

 (* if the elements `{{a,b}, c}` are already sorted with respect to the the last entry:*)
 DeleteDuplicates[Cases[x, {{_, _}, _}], (#1[[1]] == #2[[1]] &)] 
 (* if not: *)
 DeleteDuplicates[SortBy[#, Last] &@Cases[x, {{_, _}, _}], (#1[[1]] == #2[[1]] &)]

to get:

(* {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}} *)

Update: Further alternatives that preserve the ordering of the input list:

cleanUp2[x_] :=  With[{gthrd = GatherBy[Select[x, Depth[#] == 3 &], First]},
   Join @@ Pick[#, Last /@ #, Min @@ (Last /@ #)] & /@ gthrd];
cleanUp3[x_] := DeleteCases[x, Alternatives[{_Integer, _},
    {w : {_, _}, z_} /; z > Min @@ Last /@ Cases[x, {w, _}]]]; 
cleanUp4[x_] :=  Cases[x, {w : {_, _}, z_} /; z == Min @@ Last /@ Cases[x, {w, _}]];

Example:

 cleanUp3[x2]
 (* {{{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}, {{4, 14}, 2}} *)
$\endgroup$
2
$\begingroup$

enter image description here

Using MinimalBy:

list = {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 
   1}, {{4, 18}, 1}, {{4, 14}, 3}, {4, 15}, {{4, 16}, 2}, {4, 18}};

DeleteCases[list, {_?AtomQ, _?AtomQ}, {1}] // MinimalBy[Last]

{{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}}

$\endgroup$
2
$\begingroup$

Using GroupBy and Select:

lst = {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1},
       {{4, 17}, 1}, {{4, 18}, 1}, {{4, 14}, 3}, {4, 15}, {{4, 16}, 2}, {4, 18}};

First@GroupBy[Select[lst, Length[Flatten@#] > 2 &], Last, Sort]

(* {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}} *)

Edit: By @Syed's suggestion, another way:

Cases[list, {{__}, _}] // GroupBy[#, Min@Last][1] & (*Thanks, mate!*)
$\endgroup$
1
  • 1
    $\begingroup$ Try: ` Cases[list, {{__}, _}] // GroupBy[#, Min@Last][1] &` $\endgroup$
    – Syed
    Commented Apr 28, 2023 at 4:00
2
$\begingroup$
list = 
 {{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, 
  {{4, 18}, 1}, {{4, 14}, 3}, {4, 15}, {{4, 16}, 2}, {4, 18}};

KeyValueMap[List] @ GroupBy[Cases[list, {_List, _}], First -> Last, Min]

{{{4, 14}, 1}, {{4, 15}, 1}, {{4, 16}, 1}, {{4, 17}, 1}, {{4, 18}, 1}}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.