In a functional language, how to conditionally select elements to be used in zip- or zipWith-style function?
Question: I am familiar with standard `zipWith` functions which operate on corresponding
elements of two sequences, but in a functional language (or a language with
some functional features), what is the most succinct way to _conditionally_
select the pairs of elements to be zipped, based on a third sequence?

This curiosity arose while scratching out a few things in Excel.  
With numbers in A1:A10, B1:B10, C1:C10, D1, E1 and F1, I'm using a formula
like this:

    
    
    {=AVERAGE(IF((D1<=(A1:A10))*((A1:A10)<=E1),B1:B10/C1:C10))}
    

Each half of the multiplication in the IF statement will produce an array of
Boolean values, which are then multiplied (AND'ed) together. Those Booleans
control which of the ten quotients will ultimately be averaged, so it's as
though ten separate IF statements were being evaluated.

If, for example, only the second and third of the 10 values in A1:A10 satisfy
the conditions (both >=D1 and <=E1), then the formula ends up evaluating
thusly:

    
    
    AVERAGE(FALSE,B2/C2,B3/C3,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE)
    

The AVERAGE function happens to ignore Boolean and text values, so we just get
the average of the second and third quotients.

Can this be done as succinctly with Haskell? Erlang? LINQ or F#? Python? etc..

NOTE that for this particular example, the formula given above isn't entirely
correct--it was abbreviated to get the basic point across. When none of the
ten elements in A1:A10 satisfies the conditions, then ten FALSE values will be
passed to AVERAGE, which will incorrectly evaluate to 0.  
The formula should be written this way:

    
    
    {=AVERAGE(IF(NOT(OR((D1<=(A1:A10))*((A1:A10)<=E1))),NA(),
                 IF((D1<=(A1:A10))*((A1:A10)<=E1),B1:B10/C1:C10)))}
    

Where the `NA()` produces an error, indicating that the average is undefined.

## Update:

Thanks for the answers. I realized that my first question was pretty trivial,
in terms of applying a function on pairs of elements from the second and third
lists when the corresponding element from the first list meets some particular
criteria. I accepted Norman Ramsey's answer for that.

However, where I went to next was wondering whether the function could be
applied to a tuple representing corresponding elements from an arbitrary
number of lists--hence my question to Lebertram about the limits of
`zipWithN`.

Apocalisp's info on applicative functors led me to info on python's unpacking
of argument lists--applying a function to an arbitrary number of arguments.

For the specific example I gave above, averaging the quotients of elements of
lists (where `nums` is the list of lists), it looks like python can do it like
this:

    
    
    from operator import div
    
    def avg(a): return sum(a,0.0)/len(a)
    avg([reduce(div,t[1:]) for t in zip(*nums) if d<=t[0] and t[0]<=e])
    

More generally, with a function `f` and a predicate `p` (along with `avg`)
this becomes:

    
    
    avg([f(t[1:]) for t in zip(*nums) if p(t[0])])
    


Answer: What you're looking for is [Applicative
Functors](http://www.soi.city.ac.uk/~ross/papers/Applicative.html).
Specifically the "zippy" applicative from the linked paper.

In Haskell notation, let's call your function `f`. Then with applicative
programming, it would look as succinct as this:

    
    
    f d e as bs cs = if' <$> ((&&) <$> (d <=) <*> (e >=))
                         <$> as <*> ((/) <$> bs <*> cs) <*> (repeat 0)
       where if' x y z = if x then y else z
             (<*>)     = zipWith ($)
    

The result of `f` is a list. Simply take the average. To generify a little:

    
    
    f g p as bs cs = if' <$> p <$> as <*> (((Some .) . g) <$> bs <*> cs)
                                      <*> (repeat None)
    

Here, p is a predicate, so you would call it with:

    
    
    average $ fromMaybe 0 <$> f (/) ((&&) <$> (d <=) <*> (e >=)) as bs cs
    

... given the same definition of `<*>` as above.

Note: I haven't tested this code, so there might be missing parentheses and
the like, but this gets the idea across.

