Files
2025-08-03 20:16:55 -07:00

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