2

I would like define a function g[data,bins,x] which is a piecewise constant function taking value data[[i]] in the range bins[[i]][[1]] < x ≤ bins[[i]][[2]]. The difficulty is that I'd like data and bins to be lists that are input by the user. Mathematica seems to throw errors because the argument of Piecewise doesn't appear to be a list of pairs.

Here's an example with explicit values that works:

f[x_] :=
 Evaluate@Piecewise[
   Map[
    {#[[1]], #[[2]][[1]] < x <= #[[2]][[2]] } &, 
    Transpose[{{1, 2, 3}, {{0, 1}, {1, 2}, {2, 3}}}]
    ]
   ]

However, when I try to define a general function:

g[data_, bins_, x_] :=
 Evaluate@Piecewise[
   Map[
    {#[[1]], #[[2]][[1]] < x <= #[[2]][[2]] } &, 
    Transpose[{data, bins}]
    ]
   ]

I get several errors because Mathematica doesn't know if {data,bins} can be transposed. Any help would be appreciated!

rm -rf
  • 88,781
  • 21
  • 293
  • 472
Flip
  • 123
  • 3

1 Answers1

1

The simple solution is to remove Evaluate from the definition of g. This way, you're not forcing Mathematica to transpose something that is unknown (at this point). The natural evaluation mechanism of SetDelayed is sufficient to perform the transpose only when the function is actually called (at which point, it is known if data and bins can be transposed or not).

However, the drawback of this is that you end up transposing {data, bins} for every function call. While Transpose is usually an efficient and fast operation, this could easily be a significant bottleneck for more expensive functions. To do this the "right way" (there are many such), we could do the following:

gg[data_, bins_] := gg[data, bins] = 
    Function[x, Evaluate@
        Piecewise[Map[{#[[1]], #[[2]][[1]] < x <= #[[2]][[2]]} &, Transpose[{data, bins}]]]
    ]

For each pair of data and bins, the piecewise function is computed once (and the result memoized) and a pure function is returned. You can then call this function with a variable x to get:

gg[{1, 2, 3}, {{0, 1}, {1, 2}, {2, 3}}][x]

rm -rf
  • 88,781
  • 21
  • 293
  • 472