Tell me more ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I want to define

isGood[___] = False;

isGood[#] = True & /@ list

where list is a list of several million integers. What's the fastest way of doing this?

share|improve this question
2  
I'd use Scan[] instead of Map[], for starters... is there no regular pattern to these "several million integers" that can possibly be exploited? – J. M. Oct 25 '12 at 16:44
Those numbers have no pattern. – red3y3 Oct 25 '12 at 16:51

4 Answers

up vote 9 down vote accepted

As J. M. suggested:

isGood[___] = False;
list = RandomInteger[{-100000000, 100000000}, 1000000];
Scan[(isGood[#] = True) &, list]; // AbsoluteTiming

(* ==> {3.1651810, Null} *)

On my computer, this takes about 3 seconds for a million integers. Isn't this fast enough?

Retrieval of the results is also quite quick:

(*retrieve the results*)
ret = RandomInteger[{-100000000, 100000000}, 1000000];
isGood /@ ret; // AbsoluteTiming
(* ==> {1.8271045, Null} *)

Out of curiosity, I compared this to the undocumented HashTable (mentioned here) and got surprisingly poor results:

list = RandomInteger[{-100000000, 100000000}, 1000000];
h = System`Utilities`HashTable[];
 Scan[With[{i = #}, System`Utilities`HashTableAdd[h, i, True]] &, 
   list]; // AbsoluteTiming
(* ==> {26.7095277, Null} *)


(*retrieve the results*)
ret = RandomInteger[{-100000000, 100000000}, 1000000];
System`Utilities`HashTableContainsQ[h, #] & /@ ret; // AbsoluteTiming
(* ==> {1.4280817, Null} *)

We see that retrieval is a bit faster, but putting the keys into the HashTable is quite slow (unless I'm doing something wrong).

share|improve this answer

Are you sure you want to use UpValues? You can use Dispatch which is pretty fast when generating the lookup table and is equally fast when accessing values:

n = 6;
list = RandomInteger[{0, 10^(n + 1)}, {10^n}];

AbsoluteTiming[disp = Dispatch@Thread[list -> True];]
{1.6220927, Null}
Remove[isGood];
AbsoluteTiming[isGood[___] = False; Scan[(isGood[#] = True) &, list]]
{3.5982058, Null}

Query values:

test = RandomInteger[{0, 10^(n + 1)}, {10^n}];

AbsoluteTiming[Count[test /. disp, True]]
{1.9151096, 94844}
AbsoluteTiming[Count[isGood /@ test, True]]
{1.7601007, 94844}
share|improve this answer
2  
In this case he wants to use DownValues not UpValues. – Faysal Aberkane Oct 25 '12 at 20:12

This seems to be faster to define downvalues

list = RandomInteger[{-100000000, 100000000}, 1000000];
DownValues[isGood] = 
   HoldPattern[isGood[#]] :> True & /@ list; // AbsoluteTiming
isGood[___] = False;
share|improve this answer
Again, Scan[] would be preferable to using Map[] in this case... – J. M. Oct 26 '12 at 3:46
1  
@J.M., I'm saving all downvalues at once – Rojo Oct 26 '12 at 3:48

My solution is ugly, but task-specific. It builds a bitmap out of machine-sized integers in imperative fashion and uses Compile. This works reasonably in memory usage for ranges that have at least couple percent of True values.

A million integers:

n = 6;
list = RandomInteger[{0, 10^(n + 1)}, {10^n}];

Function itself:

<< Developer`

isGood = With[
     {bits = Floor[Log[2, $MaxMachineInteger + 1]],
      min = Min@list,
      max = Max@list},
     With[
      {bv = Compile[{{list, _Integer, 1}},
          Module[
           {bitvec = Table[0, {(max - min + bits - 1)~Quotient~bits}]},
           Scan[(bitvec[[(# - min)~Quotient~bits + 1]] += 
               2^((# - min)~Mod~bits)) &, Union@list];
           bitvec
           ],
          CompilationOptions -> {"ExpressionOptimization" -> True, 
            "InlineExternalDefinitions" -> True}
          ]@list},
      Compile[{{x, _Integer}},
       min <= x <= max && 
          bv[[(x - min)~Quotient~bits + 1]]~BitAnd~(2^((x - min)~Mod~bits)) != 0,
       CompilationOptions -> {"ExpressionOptimization" -> True, 
         "InlineExternalDefinitions" -> True}
       ]
      ]
     ]; // AbsoluteTiming // First

(* 0.347843 *)

Usage:

isGood /@ list // AbsoluteTiming // First

(* 0.590347 *)

Originally I wanted to solve this problem using bitwise operations of arbitrarily large integers, but the issue with that is that functional programming with bigints has large return value overheads - even when just some individual bits are twiddled.

share|improve this answer
1  
A few possible tweaks: use bits = BitLength[$MaxMachineInteger] to compute the maximum bit length, and you can use bitvec = ConstantArray[0, Quotient[max - min + bits - 1, bits]] for initialization. – J. M. Oct 27 '12 at 1:13

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.