Let's say there is a list like: l1={1,2,3,4,5,6,7,8}
If you're given some arbitrary element and a distance, how do you find the of list elements that are that distance away from the element.
For example get: {1,7}
when the following is called: [l1,4,3]
I can't quit make the connection between position and the built it Nearest[] function. Would Nearest[] even be useful in this case or should I look at actual list operations?
4 Answers
A quick thing. I'd just use normal list operations and keep it simple.
get[list_List, ele_, (dist_Integer)?Positive] :=
Module[{p, res = {}, n},
p = Flatten@Position[list, ele];
Do[
If[p[[n]] - dist >= 1,
AppendTo[res, list[[p[[n]] - dist]]]
];
If[p[[n]] + dist <= Length@list,
AppendTo[res, list[[p[[n]] + dist]]]
]
,
{n, 1, Length@p}
];
res
]
Then
get[{1, 2, 3, 4, 5, 6, 7, 8}, 4, 3]
get[{1, 2, 3, 4, 5, 6, 7, 8}, 4, 4]
get[{1, 2, 3, 4, 5, 6, 7, 8, 4}, 4, 3]
get[{1, 2, 3, 4, 5, 6, 7, 8, 4}, 4, 7]
get[{1, 2, 3, 4, 5, -5, 7, 8, 4}, -5, 3]
Bug reports are welcome and will be processed in the order they are received.
ClearAll[g]
g[l_List, e_, d_Integer?Positive] := l[[Select[1 <= # <= Length[l] &]@
Flatten @ Function[x, {d, -d} + x, Listable] @ Position[l, e]]]
Using Nasser's example inputs:
inputs = {{{1, 2, 3, 4, 5, 6, 7, 8}, 4, 3},
{{1, 2, 3, 4, 5, 6, 7, 8}, 4, 4},
{{1, 2, 3, 4, 5, 6, 7, 8}, 4, 5},
{{1, 2, 3, 4, 5, 6, 7, 8, 4}, 4, 3},
{{1, 2, 3, 4, 5, 6, 7, 8, 4}, 4, 7},
{{1, 2, 3, 4, 5, -5, 7, 8, 4}, -5, 3}};
g @@@ inputs
{{1, 7}, {8}, {}, {1, 7, 6}, {2}, {3, 4}}
Grid[Prepend[{##, g@##} & @@@ inputs, {"lst", "e", "d", "g[lst, e, d]"}], Dividers -> All]
Alternatively, you can use SequenceCases
:
ClearAll[g2]
g2[l_List, e_, d_Integer?Positive] := SequenceCases[l,
{a_, Repeated[_, {d - 1}], e} | {e, Repeated[_, {d - 1}], b_} :> Sequence[a, b],
Overlaps -> True];
g2 @@@ inputs == g @@@ inputs
True
f[l_List, r_Integer, q_Integer] := l[[Position[l, r][[1, 1]] + q]]
ll = {4, 1, 3, 8, 2, 7, 5, 10, 9, 6};
f[ll,5,3]
(* 6 *)
or obviously if you need both sides:
f[l_List, r_Integer, q_Integer] := {l[[Position[l, r][[1, 1]] + q]],
l[[Position[l, r][[1, 1]] - q]]}
-
$\begingroup$ This only returns the right side of the window. $\endgroup$ Apr 12, 2020 at 13:39
-
$\begingroup$ Using the 'both sides' solution above:
f[{1, 2}, 1, 1]
evaluates to{2, List}
which is wrong. $\endgroup$ Apr 13, 2020 at 20:41 -
$\begingroup$ The OP answered your question above ("What result do you expect for [l1, 4, 4]"): error because the left hand would fall out of the boundary of the list. Read "Error" for "List" $\endgroup$ Apr 13, 2020 at 21:07
Here is another way using list operations. Modify the error handling to suit your needs.
ClearAll@f;
f[list_List, value_, (distance_Integer)?Positive] :=
Module[{pos = FirstPosition[list, value][[1]]},
If[pos - distance < 1 || pos + distance > Length@list, Throw["Out of bounds"]];
Extract[list, {{pos - distance}, {pos + distance}}] // Flatten]
l1 = {1, 2, 3, 4, 5, 6, 7, 8};
f[l1, 4, 3]
(* {1, 7} *)
f[l1, 4, 1]
(* {3, 5} *)
f[l1, 4, 4]
(* "Uncaught Throw["Out of bounds"] returned to top level." *)
-
1$\begingroup$ hi. This does not work for all cases. Try
f[{1, 2, 3, 4, 5, 6, 7, 8, 4}, 4, 3]
it returns{1,7}
but it should be{1,7,6}
because there can be more than one element that match in the list. You only used the first one found. $\endgroup$– NasserApr 11, 2020 at 23:39 -
$\begingroup$ the list should be flat so meeting this condition isn't crucial $\endgroup$ Apr 11, 2020 at 23:58
-
$\begingroup$ @Nasser Actually according to @Ali that should return an error since there is no element to the right of the last
4
. Anyway, it is really simple to change my answer to usePosition
rather thanFirstPosition
to deal with duplicates. $\endgroup$ Apr 12, 2020 at 2:02
[l1, 4, 4]
? $\endgroup$