Skip to content

hxdhttk/30-Seconds-of-FSharp

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

30 seconds of F#

你可以在30秒或更短时间内收集有用的F#代码片段。

  • 使用 Ctrl + F 或者 command + F 来查找代码片段。
  • 代码片段基于 F#,如果你还不熟悉可以在这里学习。
  • 代码片段转译自 little-java-functions

目录

📚 Array (数组相关)

详细信息

➗ Math (数学相关)

详细信息

Array

chunk

将数组分割成特定大小的小数组。

let chunk numbers size = numbers |> Array.chunkBySize size


⬆ 回到顶部

concat

将两个数组合并为一个数组。

let concat first second = Array.concat [first; second]


⬆ 回到顶部

countOccurrences

计算数组中某个值出现的次数。

使用 Array.filter 计算等于指定值的值的总数。

let countOccurrences numbers value = numbers |> ((Array.filter ((=) value)) >> Array.length)


⬆ 回到顶部

deepFlatten

数组扁平化,需要将各元素装箱为 obj

使用递归实现,以及 Computation Expression 简化表达。

let rec deepFlatten (input: obj array) =
    [| for element in input do
           let t = element.GetType()
           if t.IsArray then
               yield! deepFlatten (element :?> obj array)
           else
               yield element |]


⬆ 回到顶部

difference

返回两个数组之间的差异。

使用 Array.except 实现。

let difference first second = Array.except second first


⬆ 回到顶部

differenceWith

从比较器函数不返回true的数组中筛选出所有值,将comparator(比较器)作为函数参数传入。

使用 Array.filterArray.exists 查找相应的值。

let differenceWith first second comparator =
    first
    |> Array.filter (fun a -> second |> Array.exists (fun b -> comparator a b) |> not)


⬆ 回到顶部

distinctValuesOfArray

返回数组的所有不同值。

使用 Array.distinct 去除所有重复的值。

let distinctValuesOfArray elements = elements |> Array.distinct


⬆ 回到顶部

dropElements

移除数组中的元素,直到传递的函数返回true为止。返回数组中的其余元素。

使用 Array.skipWhile 实现。

let dropElements elements condition = elements |> Array.skipWhile condition


⬆ 回到顶部

dropRight

返回一个新数组,从右边移除n个元素。

检查n是否短于给定的数组,返回相应的数组切片或空数组,使用 Option 实现 null 安全。

let dropRight elements n =
    match n < 0 with
    | true -> None
    | false -> let arrayLength = Array.length elements
               match n < arrayLength with
               | true -> Some elements.[.. (arrayLength - n - 1)]
               | false -> Some [||]


⬆ 回到顶部

everyNth

返回数组中的每个第n个元素。

使用 Array.indexed 创建一个包含索引的新数组,通过索引需要满足的的条件筛选原数组的值。

let everyNth elements nth =
    [| for index, element in elements |> Array.indexed do
           if index % nth = nth - 1 then
               yield element |]


⬆ 回到顶部

indexOf

查找数组中元素的索引,在不存在元素的情况下返回-1。

使用 Array.tryFindIndex 安全查找数组中元素的索引。

let indexOf elements el = elements |> Array.tryFindIndex ((=) el)
                                   |> function | Some x -> x | None -> -1


⬆ 回到顶部

lastIndexOf

查找数组中元素的最后索引,在不存在元素的情况下返回-1。

使用 Array.tryFindIndexBack 安全查找数组中元素的索引。

let lastIndexOf elements el = elements |> Array.tryFindIndexBack ((=) el)
                                       |> function | Some x -> x | None -> -1


⬆ 回到顶部

filterNonUnique

筛选出数组中的非唯一值。

let filterNonUnique elements = elements |> Array.groupBy id
                                        |> Array.filter (snd >> Array.length >> (=) 1)
                                        |> Array.map fst


⬆ 回到顶部

flatten

使数组扁平。

let flatten (elements: obj array) =
    [| for element in elements do
           let t = element.GetType()
           if t.IsArray then 
               yield! (element :?> obj array)
           else
               yield element |]


⬆ 回到顶部

flattenDepth

将数组压平到指定的深度。

let rec flattenDepth (elements: obj array) depth =
        match depth with
        | 0 -> elements
        | _ -> [| for element in elements do
                      let t = element.GetType()
                      if t.IsArray then
                          yield! flattenDepth (element :?> obj array) (depth - 1)
                      else
                          yield element |]


⬆ 回到顶部

groupBy

根据给定函数对数组元素进行分组。

使用 Arrays.groupBy 分组。

let groupBy elements func = elements |> Array.groupBy func


⬆ 回到顶部

initial

返回数组中除去最后一个的所有元素。

直接使用切片返回除最后一个之外的所有元素。

let initial (elements: 'a array) = elements.[..(elements.Length - 2)]


⬆ 回到顶部

initializeArrayWithRange

初始化一个数组,该数组包含在指定范围内的数字,传入 startend

let initializeArrayWithRange ``end`` start = [| start .. ``end`` |]


⬆ 回到顶部

initializeArrayWithValues

使用指定的值初始化并填充数组。

let initializeArrayWithValues n value = [| for _ in 1 .. n -> value |]


⬆ 回到顶部

intersection

返回两个数组中存在的元素列表。

在 a 上使用 Array.filter 来筛选包含在 b 中的值。

let intersection first second = first |> Array.filter (fun x -> set second |> Set.contains x)


⬆ 回到顶部

isSorted

如果数组按升序排序,则返回 1,如果数组按降序排序,返回 -1,如果没有排序,则返回 0

Naive implementation,将会改进。

let isSorted arr =
    match arr = (arr |> Array.sort), arr = (arr |> Array.sortDescending) with
    | true, _ -> 1
    | _, true -> -1
    | _, _ -> 0


⬆ 回到顶部

join

将数组的所有元素连接到字符串中,并返回此字符串。

使用 String.concat 将元素组合成字符串。

let join arr separator ``end`` =
    arr |> Array.map string
        |> String.concat separator
        |> (fun x -> x + ``end``)


⬆ 回到顶部

nthElement

返回数组的第n个元素。

let nthElement (arr: 'a array) n =
    match n > 0 with
    | true -> arr.[n - 1]
    | false -> arr.[arr.Length + n]


⬆ 回到顶部

pick

从对象中选择与给定键对应的键值对。

使用 Map 将所有的 seq<'a * 'b> 转换为Map。

let pick obj arr =
    arr |> Array.filter (fun x -> obj |> Map.containsKey x)
        |> Array.map (fun x -> x, obj.[x])
        |> Map


⬆ 回到顶部

reducedFilter

根据条件筛选对象数组,同时筛选出未指定的键。

使用 Array.filter 根据谓词 fn 过滤数组,以便返回条件为真的对象。 对于每个过滤的Map对象,创建一个新的Map,其中包含 keys 中的键。最后,将Map对象收集到一个数组中。

let reducedFilter data keys fn =
    data
    |> Array.filter fn
    |> Array.map (fun el -> keys |> Array.filter (fun x -> el |> Map.containsKey x)
                                 |> Array.map (fun x -> x, el.[x])
                                 |> Map)


⬆ 回到顶部

sample

从数组中返回一个随机元素。

使用 Random().NextDouble() 生成一个随机数,然后将它乘以数组的 length,然后使用 floor >> int 获得一个最近的整数,该方法也适用于字符串。

let sample (arr: 'a array) = let rnd = Random()
                             arr.[(rnd.NextDouble() * (float arr.Length)) |> (floor >> int)]


⬆ 回到顶部

sampleSize

arrayarray 大小的唯一键获取 n 个随机元素。

根据Fisher-Yates算法

let sampleSize input n =
    let rnd = Random()
    let rec inner (arr: 'a array) m =
        match m with
        | 0 -> arr
        | _ -> let i = (rnd.NextDouble() * (float m)) |> (floor >> int)
               let tmp = arr.[i]
               arr.[i] <- arr.[m]
               arr.[m] <- tmp
               inner arr (m - 1)
    let copy = input |> Array.copy
    let length = input.Length
    if n > length then (inner copy (length - 1)) else (inner copy n) |> Array.take n


⬆ 回到顶部

shuffle

将数组值的顺序随机化,返回一个新数组。

根据 Fisher-Yates 算法 重新排序数组的元素。

let shuffle input =
    let rnd = Random()
    let rec inner (arr: 'a array) m =
        match m with
        | 0 -> arr
        | _ -> let i = (rnd.NextDouble() * (float m)) |> (floor >> int)
               let tmp = arr.[i]
               arr.[i] <- arr.[m]
               arr.[m] <- tmp
               inner arr (m - 1)
    let copy = input |> Array.copy
    let length = input.Length
    inner copy (length - 1)


⬆ 回到顶部

similarity

返回出现在两个数组中的元素数组。

intersection 实现一致,因为 F# 的函数是自动泛化的不需要专门实现同一函数的泛型版本。

let similarity first second = first |> Array.filter (fun x -> set second |> Set.contains x)


⬆ 回到顶部

sortedIndex

返回值应该插入到数组中的最低索引,以保持其排序顺序。

检查数组是否按降序(松散地)排序。 建立索引的数组并使用 Array.filter 来找到元素应该被插入的合适的索引。

let sortedIndex (arr: 'a array) el =
    let isDescending = arr.[0] > arr.[1]
    [| 0 .. arr.Length - 1 |]
    |> Array.filter (fun index -> if isDescending then el >= arr.[index] else el <= arr.[index])
    |> Array.tryHead
    |> function | Some x -> x | None -> arr.Length


⬆ 回到顶部

symmetricDifference

返回两个数组之间的对称差异。

从每个数组中创建一个 Set,然后使用 Array.filter 来保持其他值不包含的值。最后,连接两个数组并创建一个新数组并返回。

let symmericDifference first second =
    [| first |> Array.filter (fun x -> set second |> Set.contains x);
       second |> Array.filter (fun x -> set first |> Set.contains x) |]
    |> Array.concat


⬆ 回到顶部

tail

返回数组中除第一个元素外的所有元素。

let tail arr = arr |> Array.tail


⬆ 回到顶部

take

返回一个从开头删除n个元素的数组。

let take arr n = arr |> Array.skip n


⬆ 回到顶部

takeRight

返回从末尾移除n个元素的数组。

使用切片语法。

let takeRight (arr: 'a array) n = arr.[(arr.Length - n)..]


⬆ 回到顶部

union

返回两个数组中任何一个中存在的每个元素一次。

let union first second = set first |> Set.union (set second) |> Array.ofSeq


⬆ 回到顶部

without

筛选出具有指定值之一的数组的元素。

let without arr elements = arr |> Array.filter (fun x -> set elements |> Set.contains x |> not)


⬆ 回到顶部

zip

根据原始数组中的位置创建元素数组。

let zip (arrays: 'a array array) =
    let maxIndex = arrays |> Array.map (fun x -> x.Length)
                          |> Array.max
    [| for index in [0 .. maxIndex - 1] do
           yield arrays |> Array.map (fun x -> if index < x.Length then Some x.[index] else None) |]


⬆ 回到顶部

zipObject

给定有效的属性标识符数组和值数组,返回将属性与值关联的对象。

let zipObject props values =
    props
    |> Array.mapi (fun index prop -> prop, if index < (values |> Array.length) then Some values.[index] else None)
    |> Map


⬆ 回到顶部

Maths

average

返回两个或两个以上数字的平均值。

let inline average (arr: ^a array when ^a : (static member (+) : ^a * ^a -> ^a)) = arr |> Array.average


⬆ 回到顶部

gcd

计算一系列数字的最大公约数(gcd)。

使用 Array.reduce 和 GCD(使用递归公式)计算一组数字的最大公约数。

let gcd numbers =
    let rec inner a b =
        match b = 0 with
        | true -> a
        | false -> inner b (a % b)
    numbers |> Array.reduce inner


⬆ 回到顶部

lcm

计算数字数组的最低公共倍数(LCM)。

使用 Array.reduce 和 LCM公式(使用递归)来计算数字数组的最低公共倍数。

let lcm numbers =
    let rec gcd' a b =
        match b = 0 with
        | true -> a
        | false -> gcd' b (a % b)
    let lcm' a b = (a * b) / (gcd' a b)
    numbers |> Array.reduce lcm'


⬆ 回到顶部

findNextPositivePowerOfTwo

查找大于或等于该值的下一个幂。

let findNextPositivePowerOfTwo value = 1 <<< Convert.ToString(value - 1, 2).Length


⬆ 回到顶部

isEven

检查数字是否是偶数。

let isEven value = (value &&& 1) = 0


⬆ 回到顶部

isPowerOfTwo

检查一个值是2的正幂。

let isPowerOfTwo value = (value > 0) && ((value &&& (~~~value + 1)) = value)


⬆ 回到顶部

generateRandomInt

生成一个介于 Int32.MinValueInt32.MaxValue 之间的随机数。

let generateRandomInt () =
    let rnd = Random()
    rnd.Next(Int32.MinValue, Int32.MaxValue)


⬆ 回到顶部

About

🎱 30 seconds to collect useful F# snippet

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • F# 100.0%