这个问题已经被要求提供更一般的背景。但是,在这个特定的背景下:
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<'a>()
for x1 in s1 do
for x2 in s2 do
m.Add(x1 |> op <| x2) |> ignore
m
|> 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
这是两组数字交叉乘积计算数字集的最有效方法。
显然,性能是O(s1 |> Seq.lenght,s2 |> Seq.length)。所以表现就像:
> 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]
> 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; ...]
但也许有一些巧妙的技巧可以让它更快?
请注意,例如,如果多列表[1..2] [1..3]得到[1; 2; 3; 4; 6],则跳过5,同时将[1..1000]与[1..1000]相乘[1..5000]至少提供了[1..100]的列表而没有跳过任何内容。但是,会有更多重复。
P.M。如果你关心投票这个问题,请花点时间解释,我可能会学到一些东西。
答案 0 :(得分:1)
之前已经发布了,基本上这将有一个O(n * m)性能,所以非常糟糕!只是把它挂在我的代码中可能会让我陷入困境。
但是,如上所述,这是一个特定的用例场景。我试图实现的是为两组数字之间的计算提供一组可能的答案。所以,实际上,我并不需要所有的答案,只需要一个合理的选项列表。
对于我的使用案例,当您每天开3到4次并且每次可以选择1到5片时,您将获得以下可能的选择范围以获得每日总数:multiplyLists [ 3; 4] [1..5] = [3; 6; 9; 12; 15; 4; 8; 16; 20。实际上它比这更复杂,但它归结为这个原则。所以,我想阻止用户在给定限制的情况下决定每天5片是可行的选择。
所以,解决方案很简单(只是很长时间没有意识到这一点; - ():
let maximize n (set: list<_>) =
let max = set.Length
if n >= max then set
else
let set = set |> Seq.sort
let nth = max / (n - 1)
let i = ref 0
[ for x in set do
if !i % nth = 0 then
yield x
i := !i + 1 ]
let inline calcSeq op (s1: 'a list) (s2: 'a list) =
let m = new HashSet<'a>()
let s1 = s1 |> maximize 100
let s2 = s2 |> maximize 100
for x1 in s1 do
for x2 in s2 do
m.Add(op x1 x2) |> ignore
m
|> 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