232 lines
5.6 KiB
FSharp
232 lines
5.6 KiB
FSharp
module common
|
|
|
|
let allIntegers = Seq.unfold(fun i -> Some(i, i + 1)) 0
|
|
|
|
let allSquares = Seq.unfold(fun (square,odd) -> Some(square, (square+odd, odd+2))) (0,1)
|
|
|
|
let multiples n =
|
|
let rec m ns =
|
|
seq {
|
|
yield ns
|
|
yield! m (ns + n)
|
|
}
|
|
m n
|
|
|
|
let divisorsWithRule rule len =
|
|
let d = Array.create (len + 1) [] // stores the divisors for each number by index
|
|
seq {1..len} |> Seq.iter (fun i ->
|
|
seq { i .. i .. len } |> Seq.iter ( fun j ->
|
|
if rule i j then d.[j] <- i :: d.[j]
|
|
)
|
|
)
|
|
d
|
|
|
|
let divisors = divisorsWithRule (<>)
|
|
let divisorsInclSelf = divisorsWithRule (fun _ _ -> true)
|
|
|
|
let rec gcd(a,b) =
|
|
if b > a then gcd (b,a) else
|
|
match b with
|
|
| 0 -> a
|
|
| b -> gcd (b, a%b)
|
|
|
|
let rec gcdI(a:bigint,b:bigint) =
|
|
if b > a then gcdI (b,a) else
|
|
match b with
|
|
| b when b = 0I -> a
|
|
| b -> gcdI (b, a%b)
|
|
|
|
let primeArray max =
|
|
let d = Array.init (max + 1) (fun i -> i)
|
|
seq {2..(max/2)} |> Seq.iter (fun i ->
|
|
seq { 0 .. i .. max } |> Seq.iter ( fun j ->
|
|
if i <> j && j <> 0 then d.[j] <- -1
|
|
)
|
|
)
|
|
d |> Array.filter ((<) 1)
|
|
|
|
let isPrimeFunByArray primes =
|
|
let primeLookup =
|
|
primes |> Array.map (fun p -> (p, true)) |> dict
|
|
(fun n -> primeLookup.ContainsKey(n))
|
|
|
|
let isPrimeFunByMax max =
|
|
primeArray max |> isPrimeFunByArray
|
|
|
|
let isPrimeI n =
|
|
if n < 2I then false
|
|
else
|
|
let limit = float n |> sqrt |> fun x -> x + 1. |> (fun n -> bigint n)
|
|
let rec loop d =
|
|
match d with
|
|
| limit -> true
|
|
| d when n % d = 0I -> false
|
|
| _ -> loop (d + 1I)
|
|
loop 2I
|
|
|
|
let compositeArray max =
|
|
let primes = primeArray max
|
|
primes
|
|
|> Seq.pairwise
|
|
|> Seq.collect (fun (p1, p2) ->
|
|
seq { (p1+1) .. (p2 - 1) }
|
|
)
|
|
|
|
let coprimeArray len =
|
|
let c = Array.create (len + 1) []
|
|
let d = divisors len
|
|
d.[1] <- [1]
|
|
let set1 = Set [1]
|
|
for i in 2 .. len do
|
|
let dis = Set d.[i]
|
|
for j in 1 .. (i - 1) do
|
|
//if not (Set.contains j dis) then
|
|
let djs = Set d.[j]
|
|
if Set.intersect dis djs = set1 then
|
|
c.[i] <- j :: c.[i]
|
|
c
|
|
|
|
|
|
let crossMapList l1 l2 =
|
|
seq { for el1 in l1 do
|
|
for el2 in l2 do
|
|
yield (el1, el2) }
|
|
|
|
let crossSelfMapList l =
|
|
crossMapList l l
|
|
|
|
let crossMap f l1 l2 =
|
|
crossMapList l1 l2 |> Seq.map (fun (el1, el2) -> f el1 el2)
|
|
|
|
let crossSelfMap f l =
|
|
crossMap f l l
|
|
|
|
let rec permutations set =
|
|
seq {
|
|
if Set.empty = set then yield [] else
|
|
for s in set do
|
|
let remaining = set |> Set.remove s
|
|
for perm in (permutations remaining) do
|
|
yield s :: perm
|
|
}
|
|
|
|
let rec slottedPermutations slots =
|
|
seq {
|
|
if List.empty = slots then yield [] else
|
|
let set = List.head slots
|
|
for s in set do
|
|
for perm in (slottedPermutations (List.tail slots)) do
|
|
yield s :: perm
|
|
}
|
|
|
|
let combinations size set =
|
|
let rec combinations acc size set = seq {
|
|
match size, set with
|
|
| n, x::xs ->
|
|
if n > 0 then yield! combinations (x::acc) (n - 1) xs
|
|
if n >= 0 then yield! combinations acc n xs
|
|
| 0, [] -> yield acc
|
|
| _, [] -> () }
|
|
combinations [] size (set |> List.ofSeq)
|
|
|
|
let fibinoci =
|
|
let rec f (c, p) =
|
|
seq {
|
|
yield c
|
|
yield! f (c + p, c)
|
|
}
|
|
f (1I,0I)
|
|
|
|
let digitCount n =
|
|
int (System.Math.Floor(System.Math.Log10 (float n)) + 1.0)
|
|
|
|
let mapChars f n =
|
|
(string n).ToCharArray()
|
|
|> Array.map f
|
|
|
|
let joinStrings =
|
|
Array.map string
|
|
>> Array.fold (fun acc i -> i + acc) ""
|
|
|
|
let numDigits =
|
|
mapChars (string >> int)
|
|
|
|
let digitsNum (ds:int[]) =
|
|
ds
|
|
|> joinStrings
|
|
|> int
|
|
|
|
let lastDigits d n =
|
|
let s = string n
|
|
s.Substring(s.Length - d)
|
|
|
|
let rec factorial n =
|
|
match n with
|
|
| 0
|
|
| 1 -> 1
|
|
| _ -> n * factorial (n - 1)
|
|
|
|
let rec factorialI n =
|
|
match n with
|
|
| n when n = 0I -> 1I
|
|
| n when n = 1I -> 1I
|
|
| _ -> n * factorialI (n - 1I)
|
|
|
|
let takeIndexes ns input =
|
|
// Take only elements that we need to access (sequence could be infinite)
|
|
let arr = input |> Seq.take (1 + Seq.max ns) |> Array.ofSeq
|
|
// Simply pick elements at the specified indices from the array
|
|
seq { for index in ns -> arr.[index] }
|
|
|
|
let arrayToRevSeq a =
|
|
let len = (Array.length a) - 1
|
|
seq {
|
|
for i in len .. -1 .. 0 do
|
|
yield a.[i]
|
|
}
|
|
|
|
let array2DFromNested a =
|
|
Array2D.init (Array.length a) (Array.length a.[0]) (fun i j -> a.[i].[j])
|
|
|
|
let strSplit t (str:string) = str.Split(',') |> Array.map t
|
|
let strSplitInt = strSplit int
|
|
let strSplitFloat = strSplit float
|
|
|
|
let isPanDigitalD digits =
|
|
let len = Seq.length digits
|
|
let range = Seq.forall (fun d -> d <= len && d > 0) digits
|
|
let unique = Set.count (Set digits) = len
|
|
range && unique
|
|
|
|
let isPanDigital n =
|
|
isPanDigitalD (numDigits n)
|
|
|
|
let isPanDigitalGroup s =
|
|
Seq.collect numDigits s |> isPanDigitalD
|
|
|
|
let letterValue (c:char) =
|
|
int c - 64
|
|
|
|
let wordValue (w:string) =
|
|
w.ToUpper()
|
|
|> Seq.map letterValue
|
|
|> Seq.sum
|
|
|
|
let floatWrap f n =
|
|
let n = float n
|
|
f n |> int64 |> (fun n -> bigint n)
|
|
|
|
let triangleNumber n =
|
|
n |> floatWrap (fun n -> n / 2.0 * (n + 1.0))
|
|
|
|
let pentagonalNumber n =
|
|
n |> floatWrap (fun n -> n / 2.0 * (3.0 * n - 1.0))
|
|
|
|
let hexagonalNumber n =
|
|
n |> floatWrap (fun n -> n * (2.0 * n - 1.0))
|
|
|
|
let revString s =
|
|
new string (s |> Seq.toArray |> Array.rev)
|
|
|
|
let isPalindrome s =
|
|
s = revString s |