I have the following:
data = {15, 25, 35, 45, 55, 65, 75, 85, 95, 105};
selector = {0, 1, 1, 0, 1, 1, 1, 0, 0, 0};
I want to create the following list from data
using selector
output = {0, 15, 15, 0, 45, 45, 45, 0, 0, 0};
The rule is given a contiguous block of 1
s, output
is created by selecting the element from data
in the position before the first 1
and creating a constant array of that element that is the same length as that block of 1
s. Else output
is zero.
Note: selector[[1]]
is always 0
My solution is the following, but it is not very "Mathematica".
foo[data_, selector_] :=
Block[
{
output = ConstantArray[0, Length[data]]
},
Do[
Which[
selector[[i]] == 0 && selector[[i + 1]] == 1,
output[[i + 1]] = data[[i]],
selector[[i]] == 1 && selector[[i + 1]] == 0,
output[[i + 1]] = 0,
1 + 1 == 2,
output[[i + 1]] = output[[i]]
],
{i, Length[data] - 1}
];
output
];
foo[data, selector] == output
True
Is there a cleaner / quicker way of solving this?
Timing
SeedRandom[1];
n = 100000;
selectorBig = RandomInteger[1, n];
selectorBig[[1]] = 0;
dataBig = RandomInteger[{15, 105}, n];
outputBig=foo[dataBig, selectorBig]; // RepeatedTiming // First
0.137602
EDIT
Adding in a compiled version for completeness (150x faster)
fooC =
Compile[
{
{data, _Integer, 1},
{selector, _Integer, 1}
},
Block[
{
output = ConstantArray[0, Length[data]]
},
Do[
Which[
selector[[i]] == 0 && selector[[i + 1]] == 1,
output[[i + 1]] = data[[i]],
selector[[i]] == 1 && selector[[i + 1]] == 0,
output[[i + 1]] = 0,
1 + 1 == 2,
output[[i + 1]] = output[[i]]
],
{i, Length[data] - 1}
];
output
],
CompilationTarget -> "C",
RuntimeOptions -> "Speed"
];
fooC[data, selector] == output
fooC[dataBig, selectorBig] === outputBig // RepeatedTiming
True
{0.000815153, True}