如何随机选择Ocaml中的元素?

时间:2011-04-25 20:32:55

标签: random ocaml

在我的OCaml程序中,我需要从一大串字符串中随机选择一个字符串。到目前为止,我尝试过两种不同的方法,每种方法都没有成功。我首先将所有字符串存储到列表中,然后从列表中随机选择一个元素:

let randomelement l =
    List.nth l (Random.int (List.length l))

但如果选择列表中的第1000个字符串,则需要很长时间。所以我把它全部放到一个集合中,认为Set.choose会从集合中返回一个随机元素。但这似乎并没有奏效。我想我有两个问题...... Set.choose如何工作,是否有更好的方法可以随机选择Ocaml中的元素?

6 个答案:

答案 0 :(得分:11)

如果您关心选择速度,则应使用其他容器。当你可以使用带有O(1)的数组,即恒定时间时,为什么使用带有O(n)访问权限或带有O(log n)设置的List。

调整您的示例:

let randomelement arr =
    let n = Random.int (Array.length arr) in
    Array.get arr n;;

答案 1 :(得分:4)

Set.chooseSet.min_elt的别名;虽然它可能不会在将来。

如果你不得不经常这样做,那么

List.nth肯定会很糟糕。

数组效果很好,但是如果你需要添加更多元素或删除元素,这可能是一本记账的噩梦。

查看Random Access Lists的实现,它们具有非常适合插入,删除,查找和基数的时间,而不受数组约束。

当我最初遇到此问题时,我将SetMap的实施扩展为包括randomnth。要扩展模块,您需要重新实现结构并添加标识函数以在两者之间进行转换。我写了一个名为XSet的新模块,其中包含以下样板:

module Make (Ord : Set.OrderedType) =
    struct
        include Set.Make(Ord)

        type impl = Empty | Node of impl * elt * impl * int

        external impl_of_t : t -> impl = "%identity"
        external t_of_impl : impl -> t = "%identity"

        ...
    end

你必须使用impl_of_t反之亦然来调用普通的Set函数,或者从传递的参数中调用你的个人函数 - 传递给你的函数的应该是Set.Make的实施t不是impl

答案 2 :(得分:3)

不,Set.choose是确定性的,我认为它已在文档中指定。我认为在当前的实现中它返回最小元素。

在哪个数据结构中首先存储了您的字符串集?获取随机元素的一种简单方法是计算您拥有的不同字符串的数量,在中间选择一个随机数K,并获得您拥有的“第K个字符串”。对于某些数据结构,这可以相当有效地完成(例如对于数组,它是一个恒定的时间操作),对其他数据结构效率较低。

答案 3 :(得分:3)

您的问题意味着您总是希望准备包含字符串的结构,然后,您将随机选择几次而不更改集合。

如果这是正确的,那么我建议将它们存储在一个数组中。这样可以最快地访问随机元素(一旦选择了随机索引就直接访问)。一旦选择了随机索引i,集合和列表实现都很难访问第i个元素(尽管对于集合,如果你不介意随机性差的随机选择,你可以在二叉树中选择一个随机路径代表集合。你不能从实现之外做到这一点,但你可以复制粘贴它并在模块中添加你的函数。)

答案 4 :(得分:2)

首先,有一个List.nth函数可以替换你的帮助函数。

let n = Random.int (List.length lst) in
    List.nth n lst ;;

(虽然这不会更快,因为我很确定它和你的助手功能完全一样)

就加速这个问题而言:如果您拥有的字符串数量是固定的,那么您可以使用一个数组,这可以加快速度,因为数组的访问时间是恒定的。

答案 5 :(得分:1)

Set.choose保证每次为给定集合选择相同的元素。它没有指定选择哪个元素,但是如果你查看它的源代码,你会看到它返回最小元素。

您最好的选择是使用阵列。如果你想要一个不可变的数据结构,那么我建议用一个整数键映射。