List 如何使用F#在没有第一项和最后一项的情况下获取子列表?
我已对整数值列表进行了排序:List 如何使用F#在没有第一项和最后一项的情况下获取子列表?,list,f#,sublist,List,F#,Sublist,我已对整数值列表进行了排序: let ls = [1..4] 没有第一个和最后一个元素,如何获得子列表?(以最佳方式) 预期结果是[2;3] 这就是我到目前为止所做的,是的,这是有效的,但我认为这不是最好的方法 [1..4] |> List.tail |> List.rev |> List.tail |> List.sort 您不需要标准的库函数来实现这一点,您只是需要一种有效的方法。定义一个包含中间结果的累加器的递归函数将是一个可行的解决方案,即使列表在终止时必须反
let ls = [1..4]
没有第一个和最后一个元素,如何获得子列表?(以最佳方式)
预期结果是[2;3]
这就是我到目前为止所做的,是的,这是有效的,但我认为这不是最好的方法
[1..4] |> List.tail |> List.rev |> List.tail |> List.sort
您不需要标准的库函数来实现这一点,您只是需要一种有效的方法。定义一个包含中间结果的累加器的递归函数将是一个可行的解决方案,即使列表在终止时必须反转 我提供了一个自定义的有区别的联合来跟踪状态,这是按照
选项类型
建模的,并带有一个额外的案例
type 'a State = Zero | One | Other of 'a
let skipFirstAndLast xss =
let rec aux acc = function
| _, [] -> List.rev acc
| Zero, x::xs -> aux acc (One, xs)
| One, x::xs -> aux acc (Other x, xs)
| (Other prev), x::xs -> aux (prev :: acc) (Other x, xs)
aux [] (Zero, xss)
[1..4] |> skipFirstAndLast // val it : int list = [2; 3]
这是一种方式:
let rec trim ls acc =
match ls, acc with
| [], _ -> acc
| h::[], acc -> List.rev acc
| h::n::t, [] -> trim t [n]
| h::t, acc -> trim t (h::acc)
let reslt = trim ls []
一个有点长的答案回应了你那天真的限定词:“以最理想的方式” 在什么方面是最优的
open System
open System.Diagnostics
open System.IO
module so29100251 =
// Daystate solution (OP)
module Daystate =
// Applied minor fixes to it
let trim = function
| [] | [_] | [_;_] -> []
| ls -> ls |> List.tail |> List.rev |> List.tail |> List.rev
// kaefer solution
module kaefer =
type 'a State = Zero | One | Other of 'a
let skipFirstAndLast xss =
let rec aux acc = function
| _, [] -> List.rev acc
| Zero, x::xs -> aux acc (One, xs)
| One, x::xs -> aux acc (Other x, xs)
| (Other prev), x::xs -> aux (prev :: acc) (Other x, xs)
aux [] (Zero, xss)
// Petr solution
module Petr =
let rec trimImpl ls acc =
match ls, acc with
| [], _ -> acc
| h::[], acc -> List.rev acc
| h::n::t, [] -> trimImpl t [n]
| h::t, acc -> trimImpl t (h::acc)
let trim ls = trimImpl ls []
// NonIdiomatic solution
module NonIdiomatic =
let trim (hint : int) (ls : 'T list) =
// trims last of rest
// Can't ask for ls.Length as that is O(n)
let ra = ResizeArray<_> (hint)
// Can't use for x in list do as it relies on .GetEnumerator ()
let mutable c = ls
while not c.IsEmpty do
ra.Add c.Head
c <- c.Tail
let count = ra.Count
let mutable result = []
for i in (count - 2)..(-1)..1 do
result <- ra.[i]::result
result
open so29100251
type Time = MilliSeconds of int64
type TestKind<'T> =
| Functional of 'T
| MeasurePerformance of int*int
[<EntryPoint>]
let main argv =
let factor = 10000000
// let maxHint = Int32.MaxValue
let maxHint = 100
let time (action : unit -> 'T) : 'T*Time =
let sw = Stopwatch ()
sw.Start ()
let r = action ()
sw.Stop ()
r, MilliSeconds sw.ElapsedMilliseconds
let adapt fn hint ls = fn ls
let trimmers =
[|
"Daystate" , adapt Daystate.trim
"kaefer" , adapt kaefer.skipFirstAndLast
"Petr" , adapt Petr.trim
"NonIdiomatic" , NonIdiomatic.trim
|]
#if DEBUG
let functionalTestCases =
[|
Functional [] , "empty" , []
Functional [] , "singleton" , [1]
Functional [] , "duoton" , [1;2]
Functional [2] , "triplet" , [1;2;3]
Functional [2;3] , "quartet" , [1;2;3;4]
|]
let performanceMeasurements = [||]
#else
let functionalTestCases = [||]
let performanceMeasurements =
[|
"small" , 10
"big" , 1000
"bigger" , 100000
// "huge" , 10000000
|] |> Array.map (fun (name, size) -> MeasurePerformance (size, (factor / size)) , name , [for x in 1..size -> x])
#endif
let testCases =
[|
functionalTestCases
performanceMeasurements
|] |> Array.concat
use tsv = File.CreateText ("result.tsv")
tsv.WriteLine (sprintf "TRIMMER\tTESTCASE\tSIZE\tHINT\tRUNS\tMEMORY_BEFORE\tMEMORY_AFTER\tGC_TIME\tRUN_TIME")
for trimName, trim in trimmers do
for testKind, testCaseName, testCase in testCases do
match testKind with
| Functional expected ->
let actual = trim 0 testCase
if actual = expected then
printfn "SUCCESS: Functional test of %s trim on testcase %s successful" trimName testCaseName
else
printfn "FAILURE: Functional test of %s trim on testcase %s failed" trimName testCaseName
| MeasurePerformance (size,testRuns) ->
let hint = min size maxHint
let before = GC.GetTotalMemory(true)
printfn "MEASURE: Running performance measurement on %s trim using testcase %s..." trimName testCaseName
let timeMe () =
for x in 1..testRuns do
ignore <| trim hint testCase
let _, MilliSeconds ms = time timeMe
let after = GC.GetTotalMemory(false)
let timeGC () =
ignore <| GC.GetTotalMemory(true)
let _, MilliSeconds msGC = time timeMe
printfn "...%d ms (%d runs), %d (before) %d (after) %d ms (GC)" ms testRuns before after msGC
tsv.WriteLine (sprintf "%s\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d" trimName testCaseName size hint testRuns before after msGC ms)
0
开放系统
开放系统诊断
开放系统
模块so29100251=
//日状态解决方案(OP)
模块日状态=
//对它进行了一些小的修正
让修剪=功能
| [] | [_] | [_;_] -> []
|ls->ls |>List.tail |>List.rev |>List.tail |>List.rev
//卡弗溶液
卡弗模块=
键入“a状态=零|一个|另一个”
让skipFirstAndLast xss=
让rec aux acc=功能
|_u,[]->List.rev acc
|零,x::xs->aux acc(一,xs)
|一个,x::xs->aux acc(其他x,xs)
|(其他前置),x::xs->aux(前置::acc)(其他x,xs)
辅助[](零,xss)
//Petr溶液
模块Petr=
让rec TRIMINPL ls acc=
将ls、acc与
|[],->acc
|h::[],acc->List.rev acc
|h::n::t,[]->trimpl t[n]
|h::t,acc->Trimpl t(h::acc)
让trim ls=trimmpl ls[]
//非惯用解
非惯用模块=
让修剪(提示:int)(ls:'T列表)=
//修剪剩下的部分
//不能要求ls.长度,因为这是O(n)
设ra=ResizeArray(提示)
//无法用于列表中的x,因为它依赖于.GetEnumerator()
设可变c=ls
而不是c.我是空的
ra.添加c.头
c Array.map(fun(name,size)->MeasurePerformance(size,(factor/size)),name,[对于1中的x..size->x])
#恩迪夫
让测试用例=
[|
功能测试用例
性能测量
|]|>Array.concat
使用tsv=File.CreateText(“result.tsv”)
tsv.WriteLine(sprintf“TRIMMER\tTESTCASE\tSIZE\tHINT\tRUNS\tMEMORY\u之前\tMEMORY\u之后\tGC\u时间\tRUN\u时间”)
对于trimName,修剪器中的修剪操作
对于testKind、testCaseName、testCase中的testCase
将testKind与
|功能性预期->
让实际值=修剪0测试用例
如果实际=预期,则
printfn“成功:在测试用例%s上对%s trim进行功能测试成功”trimName testCaseName
其他的
printfn“失败:在测试用例%s上对%s trim的功能测试失败”trimName testCaseName
|测量性能(大小、测试运行)->
let hint=最小大小maxHint
let before=GC.GetTotalMemory(true)
printfn“度量:使用testcase%s对%s trim运行性能度量…”trimName testCaseName
让我()=
对于1中的x..testRuns
忽略你似乎没有一个列表,但你的问题仍然不清楚。“最佳方式”是什么,列表的典型长度是多少等等。这里是一个很好的起点:列表不应该包含超过100个元素。如果您知道列表已经排序,那么倒序可能比最后一步排序更快:[1..4]|>List.tail |>List.rev |>List.tail |>List.rev
。有了排序,就有了所有的条件逻辑和比较--sort
是O(n logn),而不仅仅是O(n),就像rev
一样。这是正确的。感谢您指出这一点。它适用于[1..4]
但对于[1..5]
结果列表是按降序排列的。哇!我希望我能给出超过+1的答案谢谢@Petr的反馈。哇,这是我得到的最棒的答案!我明天再谈。非常感谢你!我怀疑x86更好,因为对象更小——对象引用只有原来的一半大。因此,列表中的更多节点存储在同一页面上,页面错误也更少。