Map a function conditional on elements at multiple relative positions in a list

I figure this question has many solutions, and if an answer already exists it would be nice just to be referred to it.

I need a function that 'maps' over my list and produces a list of equal length of either 1 or 0 with particular conditions that switch the the result from 1 to 0.

The result starts as 0 and is carried into the next step unless one of these conditions is met:

1. That when both the first and element is 1 we set our result to 1; this can happen on the first element of the list.

2. When the last element is 0 we set our result to 0.

3. However if we don't find a 1 at position two in any even numbered list counting from the switch to 1 before the next switch back to 0, then leave the result as 0 for the entire period.

Essentially step 3 requires that if for the period that the result could be 1 (according to steps 1. and 2.) that at least once the even numbered elements in that period have [[2]]=1.

For example if the data is {{0, 0, 1}, {1, 0, 1}, {0, 0, 1}, {1, 0, 1}, {0, 0, 1}, {1, 0, 1}, {0, 0, 0}} then the result of this algorithm is {0, 0, 0, 0, 0, 0}. Without the third condition it would yield {0, 1, 1, 1, 1, 1, 0}.

However if the data is {{0, 0, 1}, {1, 0, 1}, {0, 1, 1}, {1, 0, 1}, {0, 0, 1}, {1, 0, 1}, {0, 0, 0}} (note the third element has a 1 at position 2 which meets the criteria that is in the element that is in a odd position after the switch, in this case 1 element after), then the result should be {0, 1, 1, 1, 1, 0}.

So far I have tried a Which function in a Table. This is fine for steps 1. and 2., but not so good for 3.

Table[
Which[
i == 1 && data[[i, 1]] == 1 && data[[i, -1]] == 1, 1,
i == 1, 0,
i > 1 && (data[[i, 1]] == 1 || data[[i, 2]] == 1) &&
data[[i, -1]] == 1, 1,
i > 1 && (data[[i - 1, 1]] == 1 || newALtest[[i - 1, 2]] == 1) &&
data[[i - 1, -1]] == 1 && data[[i, -1]] == 1, 1,
i > 1, 0], {i, 1, Length[data]}]


Some example data is here

data={{0, 0, 0}, {0, 0, 0}, {0, 0, 1}, {1, 0, 1}, {0, 0, 1}, {1, 0, 1}, {0, 0, 1}, {1, 0, 1}, {0, 0, 0}, {0, 0, 0}, {1, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 1}, {0, 1, 1}, {1, 0, 0}, {0, 0, 0}, {1, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {1, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 1}, {1, 0, 1}, {0, 1, 1}, {0, 0, 0}, {0, 0, 1}, {0, 0, 1}, {1, 0, 1}, {0, 1, 1}, {0, 1, 1}, {0, 1, 1}, {0, 1, 1}, {0, 1, 1}}


Any tips about the approach to take would probably get me heading in the right direction (I'm trying steps 1. and 2. first, then using that result for another test, but I'm still mighty confused).

For the above table, the result will be

result= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1}

• -1 and -2 are perfectly valid indices. However I find your description very hard to follow, especially point 3. Please try to clarify it and perhaps show a small example of how 3 is decided.
– rm -rf
Commented Aug 26, 2013 at 5:16
• I edited your data to add missing brackets. The results still don't seem to match the problem description. Commented Aug 26, 2013 at 6:48
• Also, what exactly is a "period?" Additionally, could you please provide the result for data without condition #3 so I can see if I understand conditions #1 and #2? Commented Aug 26, 2013 at 6:51
• My mistake Mr. Wizard. The second condition had the wrong part of the element in it. Maybe it is clearer now? The period between when condition 1. is satisfied, and then condition 2. is satisfied. Commented Aug 26, 2013 at 7:08
• There appears to be a contradiction still. In one paragraph you say: "at least once the even numbered elements in that period" and in another "the criteria that is in the element that is in a odd position after the switch, in this case 1 element after" -- what does this mean? Commented Aug 26, 2013 at 7:40

1 Answer

I believe I have a solution for you, assuming we've worked out all the discrepancies in the original question.

You will need my dynamicPartition function or one of its "core function" equivalents.

process[data_List] :=
Module[{f, s1, s2},
f[_, {1, ___, 1}] = 1;
f[_, {___, 0}] = 0;
f[x_, _] := x;
s1 = Split @ Rest @ FoldList[f, 0, data];
s2 = s1; s2[[All, ;; ;; 2]] = 0;
dynamicPartition[data[[All, 2]], Length /@ s1] //
Flatten[s1 * Unitize @ Total[s2 * #, {2}]] &
]

process[data] === result


True

Here is a terse description:

• The function f is a pattern-based function that performs your steps #1 and #2

• f is used in FoldList to apply it to each sublist, keeping track of the prior value which is used in the case that neither the #1 or #2 rule matches.

• Split partitions the resulting list into "periods" as you describe them. (s1)

• The Split result is copied to s2, then s2[[All, ;; ;; 2]] = 0 replaces all values at odd positions within the periods with zeros, which is needed for condition #3.

• dynamicPartition is used to split the column-2 data into the periods.

• This data is then multiplied with the s2 data: only non-zero values at the same place in both data sets will give a positive result. Each period is then totaled, then these totals are unitized, multiplied with the original Split data (s1), and finally flattened.

• Beauty! Give my some time to decipher it. I really needed pointing in the right direction. Thanks Commented Aug 26, 2013 at 8:00
• @Cameron I took pity and added at least a basic description so you don't pull your hair out. :^) Commented Aug 26, 2013 at 8:07
• That will definitely save me some hair loss ;-) Commented Aug 26, 2013 at 8:54
• I voted for this, even though I have no clue what the code does, but only because it looks cool. Commented Aug 26, 2013 at 8:56
• I'd like to give two upvotes really, one for the answer and one for figuring out the question :-) Commented Aug 26, 2013 at 16:11