2

Now, I want to write a function for some kind of list. The input list includes many integers. Take a simple example for f[x],

lst = {3, 6, 13};

f[x_ /; (x <= lst[[1]] && x >= 1 )] := 1;
f[x_ /; (x <= (lst[[1]] + lst[[2]]) && x >= (lst[[1]] + 1)  )] := 2;
f[x_ /; (x <= (lst[[1]]+lst[[2]] + lst[[3]])&& x >= (lst[[1]] + lst[[2]] + 1))] := 3;

How to write a simple and general function f[x] for a arbitrary list ?

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
Orders
  • 1,247
  • 11
  • 20

3 Answers3

3

I would do it this way.

makeF[data : {_Integer ..}] :=
  With[{nums = Accumulate[data]},
    f[n_Integer?Positive] :=
       Module[{r = $Failed},
         Do[If[n <= nums[[i]], r = i; Break[]], {i, Length[nums]}];
         r]]

Then

makeF[{3, 6, 13}]; Table[f[i], {i, 23}]

{1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, $Failed}

and

SeedRandom[42]; data = Sort[RandomSample[Range[99], 10]]

{4, 5, 7, 16, 33, 49, 55, 67, 82, 94}

makeF[data]; Table[f[i], {i, 50, 450, 50}]

{5, 6, 7, 8, 9, 9, 10, 10, $Failed}

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
3

I am going to assume that all values in your input list are positive integers. This then is an interpolation with order zero, or index within a list.

Interpolation:

mkFn1[a_List] :=
  ListInterpolation[
    Join[{"lo"}, Range @ Length @ a, {"hi"}], 
    Join[{1}, Accumulate @ a, {Tr @ a + 1}]
    , InterpolationOrder -> 0
  ] /* Quiet

Binary search (you must load Leonid's bsearchMax):

mkFn2[a_List] := Accumulate[a] /. acc_ :> ( bsearchMax[acc, #] & )

Output is a little different:

fn1 = mkFn1[{3, 6, 13}];
fn2 = mkFn2[{3, 6, 13}];

Array[fn1, 25, 0]
Array[fn2, 25, 0]
{"lo", 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, "hi", "hi"}

{1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4}

("lo" and "hi" are arbitrary expressions I chose.)

Both methods are very fast.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
2

Not too hard:

idx = {3, 6, 13};
f = Function @@ {\[FormalX],
                 Piecewise[MapIndexed[Append[#2, #1] &,
                                      #1 <= \[FormalX] <= #2 & @@@
                                      TranslationTransform[{1, 0}][
                                      Partition[FoldList[Plus, 0, Sort[idx]], 2, 1]]],
                           Indeterminate]};

f /@ Range[22]
   {1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574