Recently, Steve wrote a blog discussing code clarity/obscurity in the context of one-line code solutions. Simply stated, the problem he solved is this. Find the largest value in an array adjacent to a zero value. Must be zillions of ways, right?
Let me start with an example. If the array in question is A,
A = [1, 5, 3, 0, 2, 7, 0, 8, 9, 1 0];
the correct answer is 8.
Steve, being an image processing guru, immediately arrived at a solution using image processing techniques. For me, not so obvious what is going on! If I inherited this code, I'd have some work cut out for me to understand it.
fs = @(A) max(A(imdilate(A == 0, [1 1 1]))); fs(A)
ans = 8
Steve then noticed his solution was only good for positive values.
B = [5 4 -1 0 -2 0 -5 8]; fs(B)
ans = 0
zero_mask = (B == 0); adjacent_to_zero_mask = imdilate(zero_mask, [1 0 1]); max_value_adjacent_to_zero = max(B(adjacent_to_zero_mask))
max_value_adjacent_to_zero = -1
Here we see Doug's answer, written without dependence on anything but MATLAB. Very nice solution, but I have to think about it a bit. Again, I know what a mask is, I see we are looking for NaN values after division by 0, so we'll find the zeros, convolve to get the neighbors of the zeros, and find the maximum of those. Whew! I'm working hard now but I get it.
mask = isnan(conv(1./B,[0 1 0],'same')); fd = @(B) max(B(isnan(conv(1./B,[0 1 0],'same')))); fd(B)
ans = -1
The next suggestion that appeared is from Jos. It's dense, but ultimately comprehensible to me. First, create a 2 row vector with the data padded at each end with the value 1, and aligned so the first value is above the 3rd, the 2nd above the 4th, etc. (i.e., shifted over by 2 elements). Check each column to see if any of the values are 0. Select the data from the columns with a zero value, and find the maximum of those values.
fj = @(X) max(X(any([1 X(1:end-1) ; X(2:end) 1]==0))) fj(A) fj(B)
fj = @(X)max(X(any([1,X(1:end-1);X(2:end),1]==0))) ans = 8 ans = -1
My turn to start over and think about the problem. First, I want to find the indices of zeros in the array. From there, I construct an array of the neighbors.
zind = find(B==0) maxcandidates = [zind-1 zind+1]
zind = 4 6 maxcandidates = 3 5 5 7
Next, I weed out values outside the range (possibly the first and last).
maxcandidates = maxcandidates((maxcandidates > 0) & (maxcandidates <= length(B)))
maxcandidates = 3 5 5 7
Now I index into my candidates and get the maximum value!
ans = -1
As Chef Tell would say, "Very simple, very easy."
I could write this algorithm in one statement, but I fear it would immediately lose clarity.
I got to wondering what result the originator of the question had in mind if there were repeated zeros. Why? Because I could possibly get a zero result? Was that intended? All the solutions here allow that, so mine does too and I don't need to do anything more. Let's check what happens.
C = [1 2 -4 0 0]; fj(C)
ans = 0
It can definitely be fun and challenging to write nifty, compact, and very dense one-liners in MATLAB. But the horror of going back to that code later, deciphering it so it can be updated or whatever, is not for me typically. I like to write code where the comments don't have to be a lot longer than the code! What are your thoughts? Post them here.