我试图在功能范例中编写一些代码来进行练习。有一种情况我头脑中有一些问题。我试图从1,100创建一个由5个唯一整数组成的数组。我已经能够在不使用函数式编程的情况下解决这个问题:
let uniqueArray = [];
while (uniqueArray.length< 5) {
const newNumber = getRandom1to100();
if (uniqueArray.indexOf(newNumber) < 0) {
uniqueArray.push(newNumber)
}
}
我可以访问lodash
,因此我可以使用它。我在思考:
const uniqueArray = [
getRandom1to100(),
getRandom1to100(),
getRandom1to100(),
getRandom1to100(),
getRandom1to100()
].map((currentVal, index, array) => {
return array.indexOf(currentVal) > -1 ? getRandom1to100 : currentVal;
});
但是这显然不会起作用,因为它总会返回true,因为索引将在数组中(我可以删除更多的工作)但更重要的是它没有检查第二次所有值都是唯一的。但是,我不太确定如何功能模拟while循环。
答案 0 :(得分:2)
这是OCaml中的一个例子,关键是你使用累加器和递归。
let make () =
Random.self_init ();
let rec make_list prev current max accum =
let number = Random.int 100 in
if current = max then accum
else begin
if number <> prev
then (number + prev) :: make_list number (current + 1) max accum
else accum
end
in
make_list 0 0 5 [] |> Array.of_list
这不能保证数组是唯一的,因为它只能通过前一个检查。您可以通过在make
和make_list
之间的闭包中隐藏哈希表并进行恒定时间查找来解决此问题。
答案 1 :(得分:1)
这是一种基于流的Python方法。
Python的懒惰流版本是生成器。它们可以通过各种方式生成,包括看起来像函数定义但使用关键字yield
而不是return
的东西。例如:
import random
def randNums(a,b):
while True:
yield random.randint(a,b)
通常,生成器用于for循环,但是最后一个生成器具有无限循环,因此如果您尝试迭代它,它将挂起。相反,您可以使用内置函数next()
来获取字符串中的下一个项目。编写一个像Haskell take
:
def take(n,stream):
items = []
for i in range(n):
try:
items.append(next(stream))
except StopIteration:
return items
return items
在Python中StopIteration
在生成器耗尽时引发。如果这发生在n
个项目之前,那么这个代码只会返回但是生成了很多,所以也许我应该将它称为takeAtMost
。如果您放弃了错误处理,那么如果没有足够的项目(可能是您想要的话)它会崩溃。无论如何,这用作:
>>> s = randNums(1,10)
>>> take(5,s)
[6, 6, 8, 7, 2]
当然,这允许重复。
为了使事物独特(并以功能方式这样做),我们可以编写一个函数,它将流作为输入并返回由唯一项组成的流作为输出:
def unique(stream):
def f(s):
items = set()
while True:
try:
x = next(s)
if not x in items:
items.add(x)
yield x
except StopIteration:
raise StopIteration
return f(stream)
这会在闭包中创建一个流,其中包含一个可以跟踪已看到的项目的集合,只会产生唯一的项目。在这里,我传递任何StopIteration
异常。如果底层生成器没有更多元素,则不再有唯一元素。我不是100%确定我是否需要明确传递异常 - (它可能会自动发生)但是看起来很干净。
像这样使用:
>>> take(5,unique(randNums(1,10)))
[7, 2, 5, 1, 6]
take(10,unique(randNums(1,10)))
将产生1-10的随机排列。 take(11,unique(randNums(1,10)))
永远不会终止。
答案 2 :(得分:0)
这是一个非常好的问题。它实际上很常见。它甚至有时被问到是一个面试问题。
这是我从0到100生成5个整数的解决方案。
let rec take lst n =
if n = 0 then []
else
match lst with
| [] -> []
| x :: xs -> x :: take xs (n-1)
let shuffle d =
let nd = List.map (fun c -> (Random.bits (), c)) d in
let sond = List.sort compare nd in
List.map snd sond
let rec range a b =
if a >= b then []
else a :: range (a+1) b;;
let _ =
print_endline
(String.concat "\t" ("5 random integers:" :: List.map string_of_int (take (shuffle (range 0 101)) 5)))
答案 3 :(得分:-1)
这是怎么回事:
const addUnique = (ar) => {
const el = getRandom1to100();
return ar.includes(el) ? ar : ar.concat([el])
}
const uniqueArray = (numberOfElements, baseArray) => {
if (numberOfElements < baseArray.length) throw 'invalid input'
return baseArray.length === numberOfElements ? baseArray : uniqueArray(numberOfElements, addUnique(baseArray))
}
const myArray = uniqueArray(5, [])