title: Is this the most efficient algorithm to calculate the cross product of two sets of numbers?
body: <p>This question has already been asked for more general contexts. However, in this specific context:</p>
  
  <pre><code>open System.Collections.Generic
  
  #time
  // s1 and s2 are both two ordered sets of numbers
  // i.e. the both s1 and s2 do not contain duplicates
  let inline calcSeq op (s1: 'a list) (s2: 'a list) =
      let m = new HashSet&lt;'a&gt;()
  
      for x1 in s1 do
          for x2 in s2 do
              m.Add(x1 |&gt; op &lt;| x2) |&gt; ignore
      m
      |&gt; Seq.toList
  
  let inline multLists s1 s2  = calcSeq (*) s1 s2
  let inline divLists s1 s2   = calcSeq (/) s1 s2
  let inline sumLists s1 s2   = calcSeq (+) s1 s2
  let inline subtrLists s1 s2 = calcSeq (-) s1 s2
  </code></pre>
  
  <p>Is this the most efficient way to calculate the set of numbers as a result of the cross product of two sets of numbers.</p>
  
  <p>Obviously the performance is O(s1 |> Seq.lenght, s2 |> Seq.length). So the performance is like:</p>
  
  <pre><code>&gt; multLists [1..5] [1..10];;
  Real: 00:00:00.002, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0
  val it : int list =
    [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 12; 14; 16; 18; 20; 15; 21; 24; 27; 30; 28;
     32; 36; 40; 25; 35; 45; 50]
  &gt; multLists [1..1000] [1..5000];;
  Real: 00:00:02.052, CPU: 00:00:02.121, GC gen0: 100, gen1: 9, gen2: 1
  val it : int list =
    [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20; 21;
     22; 23; 24; 25; 26; 27; 28; 29; 30; 31; 32; 33; 34; 35; 36; 37; 38; 39; 40;
     41; 42; 43; 44; 45; 46; 47; 48; 49; 50; 51; 52; 53; 54; 55; 56; 57; 58; 59;
     60; 61; 62; 63; 64; 65; 66; 67; 68; 69; 70; 71; 72; 73; 74; 75; 76; 77; 78;
     79; 80; 81; 82; 83; 84; 85; 86; 87; 88; 89; 90; 91; 92; 93; 94; 95; 96; 97;
     98; 99; 100; ...]
  </code></pre>
  
  <p>But maybe there are some clever tricks I can do to make this faster?</p>
  
  <p>Note, for example, that if you multLists [1..2] [1..3] you get [1;2;3;4;6], skipping 5, while multiplying [1..1000] with [1..5000] gives at least a list of [1..100] without skipping any. However, there will be duplicates further on.</p>
  
  <p>P.m. If you care to down vote this question, please take some time to explain, I might learn something.</p>