If speed is an issue, and you're using numeric values, I would go for Compile
. This will only work for data types that are compilable, such as _Integer
or _Real
, but those seem to be the only ones OP is interested in.
Here's the fastest I could come up with:
Module[{cfn1},
cfn1 = Compile[{{list, _Integer, 1}},
Module[{temp, max = First@list, maxp = 1},
Do[temp = list[[i]];
If[temp > max, max = temp; maxp = i], {i, Length@list}];
{max, maxp}
], CompilationTarget -> "C"];
singlePassC[arg : {__Integer}] := cfn1[arg];
singlePassC[{}] = {};
]
I noticed some interesting timing trends, though, compared to Mr.Wizard's function. Consider the more Mathematica-like Compile
d implementation for finding the maximum position:
Module[{cfn1},
cfn1 = Compile[{{list, _Integer, 1}},
With[{max = Max@list}, {{{max}}, Position[list, max]}],
CompilationTarget -> "C"];
twoPassC[arg : {__Integer}] := cfn1[arg][[All, 1, 1]];
twoPassC[{}] = {};
]
(* Mr. Wizard's non-compiled implementation *)
sparseArrayME[
a_] := {#, First@SparseArray[UnitStep[a - #]]["AdjacencyLists"]} &@ Max@a
All of these work:
sparseArrayME@{3, 5, 4} ===
singlePassC@{3, 5, 4} ===
twoPassC@{3, 5, 4} ===
{5, 2}
(* True *)
But notice these peculiar timings:
dat = RandomInteger[1*^9, {100000000}];
datm = RandomInteger[1*^9, {1000, 100000}];
test[f_] := f@dat // Timing // First
testm[f_] := f /@ datm // Transpose // Timing // First
funcs = {sparseArrayME, singlePassC, twoPassC};
{{"Data Type", "Sparse Array", "Single Pass C", "Two Pass C"},
Prepend[test /@ funcs, "Single Array"],
Prepend[testm /@ funcs, "Matrix"]} // TableForm
So Mr.Wizard's uncompiled SparseArray
properties is faster than a compiled Position
when applied to many smaller-sized sublists. I doubt this is because of the deeper nesting I am forced to make in twoPassC
's cfn1
which I then extract from in the actual function - that shouldn't be what takes so long.