简体   繁体   English

F# 中的列表操作

[英]List manipulation in F#

What I'm hoping to make this function do is:我希望让这个 function 做的是:

  1. Generate a list of random integers of length specified by count生成由 count 指定长度的随机整数列表

  2. Generate another random number to replace first element of list生成另一个随机数来替换列表的第一个元素

  3. Sort the list对列表进行排序

  4. Split list in half, discarding second half将列表分成两半,丢弃后半部分

  5. Discard first element of list丢弃列表的第一个元素

  6. Repeat 2-5 unless list is empty重复 2-5,除非列表为空

What I have so far (but not working) is below.到目前为止我所拥有的(但没有工作)如下。 What is the matter with it?它有什么问题?

let go count =
    let rec cut l = 
        if List.length l = 0 then l
        printfn "%A" l
        let list = System.Random().Next(100)::List.tail l
        let cut list = 
            let firstHalf= list |> Seq.take (List.length list / 2) |> Seq.toList
            firstHalf
        let listSorted = List.sort list
        cut (List.tail listSorted)
    let r = System.Random()
    let list1 = List.init count (fun numbers -> r.Next(100))
    printfn "List = %A" list1
    cut list1

A few tips:一些提示:

  • Don't test if a list is empty by List.length L = 0. Each test will take as long as the amount of elements in the list.不要通过 List.length L = 0 测试列表是否为空。每次测试所需的时间与列表中元素的数量一样长。 Test with pattern matching instead, that's (almost) instantanteous:改为使用模式匹配进行测试,这(几乎)是瞬时的:

  • Don't instantiate a new instance of a random number generator each time your cut function is called: let list = System.Random()... .不要在每次调用cut function 时实例化随机数生成器的新实例: let list = System.Random()... Doing that means that you're likely to get the same numbers (each instantiaion seeds the generator with the current system time).这样做意味着您可能会得到相同的数字(每个实例化都使用当前系统时间为生成器播种)。 Just move your declaration r = System.Random() up a bit, and use that generator throughout your code.只需将您的声明r = System.Random()向上移动一点,并在整个代码中使用该生成器。

example:例子:

let rec cut l =
    match l with
    | [] -> // the list is empty, end the recursion here
    | head::tail -> // the list consists of the head element and the rest
                    // you can refer to head and tail in your code here
                    let newlist = r.next(100) :: tail
  • You're declaring a function called 'cut' inside your recursive 'cut' function, which means that the last call to 'cut' in your recursive function actually calls the non-recursive one you defined inside. You're declaring a function called 'cut' inside your recursive 'cut' function, which means that the last call to 'cut' in your recursive function actually calls the non-recursive one you defined inside. Use different names there.在那里使用不同的名称。

  • You've written 'if List.length l = 0 then l', which (apart from not using a pattern match) also presents a problem: an 'if' in F# is an expression, like the ?您已经编写了“if List.length l = 0 then l”,这(除了不使用模式匹配)也存在问题:F# 中的“if”是一个表达式,例如? operator in C#. C# 中的运算符。 In C# that would mean something like在 C# 中,这意味着类似

    (l.Count == 0)? l: //other case missing! error! danger!

  • Another tip: once your list is sorted, you don't need to sort again each time you add a new random element.另一个提示:一旦你的列表被排序,你不需要在每次添加一个新的随机元素时再次排序。 You can write code that inserts a new element in a sorted list that would be more efficient than adding an element and sorting afterwards.您可以编写在排序列表中插入新元素的代码,这比添加元素和事后排序更有效。 I'll leave the insert-into-sorted-list as an excercise.我将把 insert-into-sorted-list 作为练习。

I hope these tips are useful.我希望这些提示有用。

here is my try...这是我的尝试...

let go count = 
    System.Random() |> fun rnd ->  // With ranomizer ... (we will need it)
        let rec repeat = function  // So we got recursion 
            | x::xs when xs.Length <> 1 ->       // while we have head and tail
                printfn "%A" xs
                rnd .Next(100) :: (List.tail xs) // Add random value
                |> Seq.sort                      // Sort
                |> Seq.take( abs(xs.Length /2) ) // Make a half
                |> Seq.skip 1                    // Remove first (just skip)
                |> List.ofSeq                    // Make the list
                |> repeat                        // So and repeat
            | x::xs -> printfn "%A" xs
            | _ -> ()              // If we have no head and tail
        repeat <| List.init count (fun _ -> rnd.Next(100)) // do it with our random list

Here it is as simple as making functions for each of your statements.在这里,它就像为每个语句创建函数一样简单。

let rnd = new System.Random()

let genList n = 
    [for i = 0 to n-1 do yield rnd.Next()]

let replaceHead v lst = match lst with
                        | [] -> []
                        | (x::xs) -> (v::xs)

let splitInHalf lst = 
    let len = (lst |> List.length) / 2
    let rec loop n lst = 
        match (n,lst) with
        | 0,_ -> []
        | _,[] -> []
        | _,(x::xs) -> x :: (loop (n-1) xs)
    loop len lst


let start n = 
    let lst = genList n
    let rec loop l = 
        match l with
        | [] -> []
        | ls -> match ls |> replaceHead (rnd.Next()) 
                         |> List.sort 
                         |> splitInHalf with
                | [] -> []
                | xs -> xs |> List.tail |> loop

    loop lst

start 1

It does look like homework:) But here is my take on it:它看起来确实像家庭作业:) 但这是我的看法:

#light

// Create random integer sequence
let random_integers_of_length l  = 
    (l, new System.Random()) 
        |> Seq.unfold (fun (c, rnd) -> if c = 0 then None else Some (rnd.Next(), (c-1, rnd))) 
        |> Seq.cache

let rec mutate numbers =
    printfn "%A" (List.ofSeq numbers);                          // pretty print the list
    match numbers with                                  
    | _ when (Seq.length numbers) <= 1 -> printfn "Done.."      // if length is 1 or 0 we can stop.
    | _ ->
        numbers
            |> Seq.skip 1                                       // discard first element 
            |> Seq.append (random_integers_of_length 1)         // append random number at the start 
            |> Seq.sort                                         // sort 
            |> Seq.take ((Seq.length numbers) / 2)              // take the first half, ignore the rest
            |> Seq.skip 1                                       // discard first element 
            |> mutate                                           // do it again.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM