So I have a seq of integers. I'd like to pick every other element but only if the element preceding it is positive. For instance, given this input:
4, 9, -1, 8, 3, 20, -1, 7
I want to get this output:
9, 20
(Context: these values represent segments of text where a certain style has been applied. The 4, 9 pair indicates the user selected characters 4, 9 (exclusive) and clicked on "Bold". When the user "Unblods" only the first member of each pair becomes -1. So in order to find all "active" styles I need to filter those with -1 out)
I am looking for both a Javascript and a Clojure solution (as this code needs to run both in the browser side and the server side).
Here's a possible JS impl.:
styleList.map(function(curr, i) {
if (i % 2 == 1)
return (styleList[i - 1] >= 0) ? curr : -1;
else
return -1;
}).filter(function(curr) { return curr >= 0 })
I don't like this solution: the function that I pass to .map() uses the index i to inspect the previous value. This feels awkward. I am looking for a solution which is more functional.
Edit
Here's another solution which I don't like (again: not very functional due to the mutations to the arr object):
var arr = [];
styleList.reduce(function(prev, curr) {
arr.push(prev == -1 ? -1 : curr);
return curr;
});
arr.filter(function(curr, i) {
return i % 2 == 1 && curr >= 0;
});
Edit 2
Here's what @CandiedOrange has suggested (JS impl. using the underscore library):
_.zip(styleList, styleList.slice(1)).
slice(0, -1).
filter(function(pair, i) { return i % 2 == 0 }).
filter(function(pair) { return pair[0] >= 0 }).
map(function(pair) { return pair[1] })
comments:
.filter calls. Still, I think it is better to keep them separated as the i % 2 == 0 is an artifact of the impl. whereas the pair[0] >= 0 is the "real business logic" needed here.Edit 3
What's bothering me here, is the non functional (imperative) solution is quite trivial:
var result = [];
styleList.forEach(function(curr, i) {
if (i % 2 == 1 && styleList[i - 1] >= 0)
result.push(curr);
});
Sure it's not as terse as the Clojure solution but relies on fewer constructs so a JS developer is more likely to arrive at this than a Clojure developer is likely to arrive at the Clojure solution (which requires acquaintance with ->> partition first second map and filter)
In Clojure:
(->> your-list
(partition 2)
(filter #(pos? (first %)))
(map second))
Edit: explanation as requested by @CandiedOrange:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With