Mathematica Asked by Kenneth Eaves on June 4, 2021
I have a list of integers from 0-99, but some of the integers have been randomly removed.
I want to pick a random integer that is still in the list, let’s call it ‘a’ but if a+1, a+2, and a+3 are not also in the list I need to pick a new random integer from the list and check again until I get a number that works.
Here is a procedural approach that does not require the list to be sorted.
I will first make some test data:
testlist = RandomSample[Range[0, 99], 50];
Then define a selector function:
testlist = RandomSample[Range[0, 99], 50];
ClearAll[selector]
selector[list_] :=
TimeConstrained[
Module[{choice},
While[!
ContainsAll[list, (choice = RandomChoice[list]) + {0, 1, 2}]];
choice
],
0.5,
"None found"
]
selector[testlist]
Wrapping the function in TimeConstrained
ensures that, in case there are no such elements, the function won't get stuck in an endless loop. The return value could be the default ($Aborted
), or it could be modified to taste as shown above. For example:
selector[Range[0, 99, 2]]
(* Out: None found *)
Correct answer by MarcoB on June 4, 2021
To create some data for testing we get even numbers <100 and insert one odd number:
d = Table[i, {i, 0, 99, 2}];
d = Insert[d, 33, 18];
Now we can pick out a sequence of 3 integers in a row by:
SequenceCases[d, {x_, y_, z_} /; z == (y + 1) == x + 2, 1]
(* {{32, 33, 34}} *)
If you only want the first number, you would say:
SequenceCases[d, {x_, y_, z_} /; z == (y + 1) == x + 2 -> x, 1][[1]]
(* 32 *)
Answered by Daniel Huber on June 4, 2021
Here's a way that constructs a set of candidates by sorting the list and then breaking it into runs of consecutive elements and only keeping elements with enough successors to be viable. This is probably a good approach if you are going to be making multiple draws.
RandomSeed[1337];
test = RandomInteger[{0, 99}, 95]
(* {37, 84, 80, 98, 26, 32, 51, 65, 19, 33, 10, 88, 25, 13,
77, 68, 20, 39, 27, 83, 89, 75, 78, 87, 22, 58, 94, 49,
70, 73, 60, 44, 59, 86, 30, 12, 90, 5, 55, 63, 38, 35,
72, 81, 31, 36, 29, 93, 95, 8, 34, 15, 9, 42, 52, 50,
48, 4, 92, 71, 56, 2, 69, 54, 74, 91, 45, 64, 0, 82,
96, 85, 16, 6, 7} *)
runs = Split[Sort[test], Subtract /* EqualTo[-1]];
Only runs of length $ > 3 $ will contain elements $ a $ such that $ a + 1 $, $ a + 2 $, and $ a + 3 $ are present:
longRuns = Select[runs, Length /* GreaterThan[3]];
Drop
elements that don't have enough successors and flatten.
candidates = Flatten[Drop[#, -3] & /@ longRuns]
(* {4, 5, 6, 7, 29, 30, 31, 32, 33, 34, 35, 36, 48, 49, 68,
69, 70, 71, 72, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
90, 91, 92, 93} *)
Now you can make random draws.
RandomChoice[candidates, 10]
(* {34, 85, 89, 90, 4, 81, 83, 29, 93, 85} *)
Answered by Pillsy on June 4, 2021
First generate a random sample of integers between 0 and 99 (and this can be with or without replacement - but I've used "without replacement" in the example):
nOriginal = 60;
original = RandomSample[Range[0, 99], nOriginal]
Now find all of the available starting numbers (a) that have a+1, a+2, and a+3 available:
available = Select[original,
MemberQ[original, # + 1] && MemberQ[original, # + 2] && MemberQ[original, # + 3] &]
Now you can select from available
with or without replacement as appropriate for your sampling objective.
This approach should work whether or not the original list has duplicate numbers or not. (However, this approach is much slower than that of @Pillsy.)
Answered by JimB on June 4, 2021
Since the input list not too large, we can also play with alternative approaches, among them RelationGraph
:
SeedRandom[1]
length = 60;
inputlist = RandomSample[Range[0, 99], length]
{80, 14, 0, 67, 3, 65, 23, 68, 74, 15, 24, 4, 83, 70, 1, 30, 48, 25, 44, 73, 69, 56, 47, 28, 92, 26, 75, 10, 43, 33, 81, 18, 38, 29, 84, 17, 27, 85, 5, 40, 82, 22, 2, 39, 36, 20, 99, 46, 52, 54, 35, 9, 63, 42, 95, 89, 98, 49, 64, 45}
rg = RelationGraph[#2 == # + 1 &, inputlist, ImageSize -> Large,
VertexSize -> .7, VertexStyle -> White,
VertexLabels -> Placed["Name", Center]]
candidates = VertexList[rg, _?(Length[VertexOutComponent[rg, #]] >= 4 &)]
{80, 0, 67, 23, 24, 1, 25, 44, 26, 43, 81, 27, 82, 22, 2, 46, 42, 45}
HighlightGraph[rg, Style[#, Orange] & /@ candidates]
Use RandomSample
or RandomChoice
to pick any number of elements from candidates
:
SeedRandom[123]
randomselection = RandomSample[candidates, 5]
{2, 80, 67, 25, 44}
HighlightGraph[rg,
Join[Style[# + Range[3], Yellow] & /@ randomselection, List /@ randomselection]]
Answered by kglr on June 4, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP