3
$\begingroup$

For the following let me use this notation:

$\qquad \text{data}=\{\{x_1,y_{11}\}, \{x_1,y_{12}\},\{x_1,y_{1N}\},\,\dots,\,\{x_2,y_{21}\}, \{x_2,y_{22}\},\{x_2,x_{2M}\},\,\dots\}$,

where $M\neq N$. What I'm trying to find are the smallest values, $\{\{x_1,y_{11}\}, \{x_2,y_{21}\},\dots\}$, and the largest values, $\{\{x_1,y_{1N}\}, \{x_2,y_{2M}\},\,\dots\}$

As an example, expressed in the Wolfram Language:

data = 
 {{0.2,0.255556}, {0.2,0.411111}, {0.2,0.566667}, {0.2,0.722222}, {0.2,0.877778}, {0.2,1.03333}, {0.2,1.18889}, {0.2,1.34444}, {0.2,1.5},
  {0.4,0.411111}, {0.4,0.566667}, {0.4,0.722222}, {0.4,0.877778}, {0.4,1.03333}, {0.4,1.18889}, {0.4,1.34444}, {0.4,1.5},
  {0.6,0.566667}, {0.6,0.722222}, {0.6,0.877778}, {0.6,1.03333}, {0.6,1.18889}, {0.6,1.34444}, {0.6,1.5}, 
  {0.8,0.722222}, {0.8,0.877778}, {0.8,1.03333}, {0.8,1.18889}, {0.8,1.34444}, {0.8,1.5}, 
  {1.,1.03333}, {1.,1.18889}, {1.,1.34444}, {1.,1.5},{1.2,1.18889}, {1.2,1.34444}, {1.2,1.5}, {1.4,1.5}}

SmallestValues = 
  {{0.2, 0.255556}, {0.4, 0.411111}, {0.6, 0.566667}, {0.8, 0.722222}, {1., 1.03333}, {1.2, 1.18889}, {1.4, 1.5}}
BiggestValues = 
  {{0.2, 1.5}, {0.4, 1.5}, {0.6, 1.5}, {0.8, 1.5}, {1., 1.5}, {1.2, 1.5}, {1.4, 1.5}}

My problem is that I honestly can't think of a way to get this done in Mathematica. I'm used to python coding and there I would probably change the type from a list to something like a matrix and then manipulate this using for-loops, but this seems rather inefficient and is presumably not necessary here.

$\endgroup$
1
  • $\begingroup$ Do you mean "from" instead of "form"? $\endgroup$
    – user64494
    May 3, 2019 at 18:52

8 Answers 8

6
$\begingroup$
Join @@ Values @ GroupBy[data, First, MinimalBy[Last]]

{{0.2, 0.255556}, {0.4, 0.411111}, {0.6, 0.566667}, {0.8,   0.722222}, {1., 1.03333}, {1.2, 1.18889}, {1.4, 1.5}}

Join @@ Values @ GroupBy[data, First, MaximalBy[Last]]

{{0.2, 1.5}, {0.4, 1.5}, {0.6, 1.5}, {0.8, 1.5}, {1., 1.5}, {1.2,   1.5}, {1.4, 1.5}}

$\endgroup$
3
$\begingroup$

If your data is guaranteed to be ordered consecutively for the same $x$, then:

groups = SplitBy[data, #[[1]] &];
SmallestValues = groups[[All, 1]];
BiggestValues = groups[[All, -1]];

If not, you can look into GroupBy function and the code will be similar.

$\endgroup$
3
$\begingroup$

This works even if the data are out of order:

g = Gather[Sort[data], #1[[1]] == #2[[1]] &];

Map[Sort, g][[All, 1]]

{{0.2, 0.255556}, {0.4, 0.411111}, {0.6, 0.566667}, {0.8, 0.722222}, {1., 1.03333}, {1.2, 1.18889}, {1.4, 1.5}}

Map[Sort, g][[All, -1]]

{{0.2, 1.5}, {0.4, 1.5}, {0.6, 1.5}, {0.8, 1.5}, {1., 1.5}, {1.2, 1.5}, {1.4, 1.5}}

$\endgroup$
3
$\begingroup$

You may compose a few functions together to collect your results. There are a few ways to compose the functions.

With Query and RightComposition

{smallest, biggest} = 
 Query[GroupBy[First -> Last] /* KeyValueMap[Thread[{##}] &] /* Transpose, MinMax]@data

With Map and Prefix.

{smallest, biggest} = 
 Transpose@KeyValueMap[Thread[{##}] &, MinMax /@ GroupBy[First -> Last]@data]

Both give

{
 {{0.2,0.255556},{0.4,0.411111},{0.6,0.566667},{0.8,0.722222},{1.,1.03333},{1.2,1.18889},{1.4,1.5}},
 {{0.2,1.5},{0.4,1.5},{0.6,1.5},{0.8,1.5},{1.,1.5},{1.2,1.5},{1.4,1.5}}
}

Hope this helps.

$\endgroup$
3
$\begingroup$
KeyValueMap[List]@GroupBy[data, First -> Last, Min]

{{0.2, 0.255556}, {0.4, 0.411111}, {0.6, 0.566667}, {0.8, 0.722222}, {1., 1.03333}, {1.2, 1.18889}, {1.4, 1.5}}

KeyValueMap[List]@GroupBy[data, First -> Last, Max]

{{0.2, 1.5}, {0.4, 1.5}, {0.6, 1.5}, {0.8, 1.5}, {1., 1.5}, {1.2, 1.5}, {1.4, 1.5}}

Both at once:

KeyValueMap[List]@GroupBy[data, First -> Last, MinMax]

{{0.2, {0.255556, 1.5}}, {0.4, {0.411111, 1.5}}, {0.6, {0.566667, 1.5}}, {0.8, {0.722222, 1.5}}, {1., {1.03333, 1.5}}, {1.2, {1.18889, 1.5}}, {1.4, {1.5, 1.5}}}

You can leave out the KeyValueMap[List]@ part and only use the GroupBy part if you want to have an association instead of a list.

$\endgroup$
1
$\begingroup$
mm = Merge[MinMax] @ MapApply[#1 -> {##2} &] @ data;

AssociationThread[{"Min", "Max"} -> #] & /@ mm // Dataset

enter image description here

$\endgroup$
1
$\begingroup$

Using SortBy and SplitBy:

data = {{0.2, 0.255556}, {0.2, 0.411111}, {0.2, 0.566667}, {0.2, 
    0.722222}, {0.2, 0.877778}, {0.2, 1.03333}, {0.2, 1.18889}, {0.2, 
    1.34444}, {0.2, 1.5}, {0.4, 0.411111}, {0.4, 0.566667}, {0.4, 
    0.722222}, {0.4, 0.877778}, {0.4, 1.03333}, {0.4, 1.18889}, {0.4, 
    1.34444}, {0.4, 1.5}, {0.6, 0.566667}, {0.6, 0.722222}, {0.6, 
    0.877778}, {0.6, 1.03333}, {0.6, 1.18889}, {0.6, 1.34444}, {0.6, 
    1.5}, {0.8, 0.722222}, {0.8, 0.877778}, {0.8, 1.03333}, {0.8, 
    1.18889}, {0.8, 1.34444}, {0.8, 1.5}, {1., 1.03333}, {1., 
    1.18889}, {1., 1.34444}, {1., 1.5}, {1.2, 1.18889}, {1.2, 
    1.34444}, {1.2, 1.5}, {1.4, 1.5}};

t1 = data // SortBy[#, First] & // SplitBy[#, First] & // Map[First]
t2 = data // SortBy[#, First] & // SplitBy[#, First] & // Map[Last]

Prepend[
  Join[t1, t2, 2][[All, {1, 2, 4}]]
  , {"First", "Min", "Max"}] //
 Grid[#
   , Alignment -> {Left, Left, Left, Center}
   , ItemSize -> {{3, 5, 2}, 1}
   ] &

enter image description here

$\endgroup$
1
$\begingroup$

An alternative method using GatherBy:

(x |-> {First /@ x, Last /@ x})@GatherBy[data, First]

Both give:

 {
 {{0.2,0.255556},{0.4,0.411111},{0.6,0.566667},{0.8,0.722222},{1.,1.03333},{1.2,1.18889},{1.4,1.5}},
 {{0.2,1.5},{0.4,1.5},{0.6,1.5},{0.8,1.5},{1.,1.5},{1.2,1.5},{1.4,1.5}}
 }
$\endgroup$

Your Answer

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

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