# Selecting data from a list

Let's create a simple data list

Clear["Global*"];

data = Table[{i, Sin[i]}, {i, 0, 6 \[Pi], 0.01}];
L0 = ListPlot[data]


Now I want to find for which values of $$x$$ we have let's say $$y = 0.5$$. Note that my actual data do not correspond to a known function (e.g., sin()), so the solution should not take into account the function but purely the data list.

Any suggestions?

• Will it always be “around” that value, for the whole of the function/plot? Perhaps an intersection with a line kind of thing could work? Commented May 30, 2020 at 17:34

There are no values for which the ordinate is exactly 0.5 in your list, so you will have to decide for yourself how close is close enough:

For instance, if a tolerance of 0.01 is sufficiently close, then:

Cases[data, {x_, y_} /; Round[y, 0.01] == 0.5 :> x]
(* Out: {0.52, 2.62, 6.81, 8.9, 13.09, 15.18, 15.19} *)


If you want a stricter tolerance, e.g. 0.001, then:

Cases[data, {x_, y_} /; Round[y, 0.001] == 0.5 :> x]
(* Out: {13.09} *)


We can put this together in a function:

ClearAll[selector]
selector[data_, desiredVal_, tolerance_] :=
Cases[data, {x_, y_} /; Round[y, tolerance] == desiredVal :> x]

selector[data, 0.5, 0.01]
(* Out: {0.52, 2.62, 6.81, 8.9, 13.09, 15.18, 15.19} *)


If, on the other hand, you would like to use an interpolation to determine the value of x (perhaps not present in your dataset, but obtained by interpolation from it) for which $$y=0.5$$ exactly, you could use the following method to find all zeros of a function over a range I've learned on this site (but currently can't find a link for, will update):

int = Interpolation[data];

First@Last@
Reap@
NDSolve[
{f'[x] == int'[x], f[0] == int[0], WhenEvent[f[x] == 0.5, Sow[x]]},
f, Evaluate@{x, MinMax[ data[[All, 1]] ]}
]

(* Out: {0.523599, 2.61799, 6.80678, 8.90118, 13.09, 15.1844} *)

• Cases[data, {x_, y_} /; Round[y, 0.01] == 0.5 :> {x, y}] is probably closer to what the OP is looking for. Commented May 30, 2020 at 17:38
• @Rohit Possibly; but I read the question as only asking the values of $x$ that are associated with a given y; not the corresponding y. OP might not care about the $y$ since it is what they are selecting for, so it is implicit in the request. Commented May 30, 2020 at 17:48
• Please note that InterpolationOrder of Interpolation is 3 by default, this may not correspond with what is wanted. Commented May 30, 2020 at 18:21
• @kirma that’s true, but the differences In the results are very small, whereas the default interpolation order leads to much faster calculations than InterpolationOrder -> 1. Commented May 30, 2020 at 18:34

Update

To get the n nearest values

nfun[.5, 6]

(*
{{1310, 0.500027}, {891, 0.501021}, {263, 0.498262}, {682, 0.502782}, {53, 0.49688}, {1519, 0.503775}}
*)


Here is one way

nfun = Nearest[data[[All, 2]] -> {"Index", "Element"}];
nfun[.5]

(* {{1310, 0.500027}} *)


The value closest to 0.5 is 0.500027 at index 1310.

• That's only one value. In this example, there are six values of $x$ for which $y = 0.5$. Commented May 30, 2020 at 17:15
• No, there are none that equal 0.5. Select[data, #[[2]] == 0.5 &] is an empty list. Commented May 30, 2020 at 17:16
• So, we need to find all (six in this case) values of $x$ for which $y$ is close to 0.5. Commented May 30, 2020 at 17:21
• One comment: the output should explicitly give the values of $x$ not their position in the list. Commented May 30, 2020 at 17:24
• @Vaggelis_Z I updated my answer. You will have to define what "close" means. Commented May 30, 2020 at 17:24

Here's an incredibly dumb solution that tries to find values of $$x$$ that correspond to the linear piecewise interpolation between data points. (Frankly I find the formulation of the question imprecise for other interpretations.) For some reason SequenceCases is much slower (like thousands of times, at least) than it should really be...

With[{y0 = 0.5},
SequenceCases[
Table[{i, Sin[i]}, {i, 0, 6 Pi, 0.01}],
l : {{x1_, y1_}, {x2_, y2_}} /; y1 <= y0 <= y2 || y2 <= y0 <= y1 :>
(x /. First@Quiet@
Solve[Interpolation[l, InterpolationOrder -> 1][x] == y0, x]),
Overlaps -> True]]


{0.523605, 2.61799, 6.80679, 8.90118, 13.09, 15.1844}

@MarcoB's NDSolve trick is maybe cleaner version of the same (although it would be even nicer if one could just get all roots with Solve of a single Interpolation).

dataSubset=Pick[data,Unitize[Clip[data[[All,2]], {0.5-0.01, 0.5+0.01},{0,0}]],1]


{{0.52, 0.49688}, {0.53, 0.505533}, {2.61, 0.506907}, {2.62, 0.498262}, {6.8, 0.494113}, {6.81, 0.502782}, {8.89, 0.50965}, {8.9, 0.501021}, {8.91, 0.492342}, {13.08, 0.491342}, {13.09, 0.500027}, {13.1, 0.508661}, {15.18, 0.503775}, {15.19, 0.495112}}

FindClusters[Rule@@@dataSubset]


{{0.49688, 0.505533}, {0.506907, 0.498262}, {0.494113, 0.502782}, {0.50965, 0.501021, 0.492342}, {0.491342, 0.500027, 0.508661}, {0.503775, 0.495112}}

Rule@@@dataSubset//FindClusters[#]/.Reverse[#,{2}]&


{{0.52, 0.53}, {2.61, 2.62}, {6.8, 6.81}, {8.89, 8.9, 8.91}, {13.08, 13.09, 13.1}, {15.18, 15.19}}

Length@%
`

6