Список манипуляций в F # - PullRequest
6 голосов
/ 03 июня 2011

Я надеюсь, что эта функция сделает:

  1. Создание списка случайных целых чисел длины, указанной в count

  2. Создать другое случайное число для замены первого элемента списка

  3. Сортировать список

  4. Разделить список пополам, отбрасывая вторую половину

  5. Отменить первый элемент списка

  6. Повторять 2-5, если список не пуст

Что у меня есть ((но не работает) ниже.Что с ним?

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

Ответы [ 4 ]

7 голосов
/ 03 июня 2011

Несколько советов:

  • Не проверяйте, является ли список пустым с помощью List.length L = 0. Каждый тест занимает столько же времени, сколько количество элементов в списке. Вместо этого протестируйте сопоставление с образцом, это (почти) мгновенно:

  • Не создавайте новый экземпляр генератора случайных чисел каждый раз, когда вызывается ваша cut функция: let list = System.Random().... Это означает, что вы, вероятно, получите одни и те же числа (каждый экземпляр запускает генератор с текущим системным временем). Просто немного продвиньте вашу декларацию r = System.Random() и используйте этот генератор в коде.

пример:

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
  • Вы объявляете функцию с именем 'cut' внутри своей рекурсивной функции 'cut', что означает, что последний вызов 'cut' в вашей рекурсивной функции фактически вызывает нерекурсивную функцию, которую вы определили внутри. Используйте там разные имена.

  • Вы написали «если List.length l = 0, то l», что (помимо не использования сопоставления с шаблоном) также представляет проблему: «if» в F # - это выражение, подобное ? оператор в C #. В C # это будет означать что-то вроде

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

  • Еще один совет: как только ваш список отсортирован, вам не нужно сортировать снова каждый раз, когда вы добавляете новый случайный элемент. Вы можете написать код, который вставит новый элемент в отсортированный список, который будет более эффективным, чем добавление элемента и его последующая сортировка. Я оставлю вставку в отсортированный список в качестве упражнения.

Надеюсь, эти советы полезны.

2 голосов
/ 03 июня 2011

Здесь все так же просто, как создавать функции для каждого из ваших утверждений.

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
2 голосов
/ 03 июня 2011

вот моя попытка ...

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
0 голосов
/ 03 июня 2011

Это выглядит как домашнее задание :) Но вот мое мнение:

#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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...