简体   繁体   English

在Haskell中生成所有可能的路径

[英]Generating All Possible Paths in Haskell

I am very bad at wording things, so please bear with me. 我的措辞非常糟糕,所以请耐心等待。

I am doing a problem that requires me to generate all possible numbers in the form of a lists of lists, in Haskell. 我正在做一个问题,需要我在Haskell中以列表列表的形式生成所有可能的数字。

For example if I have x = 3 and y = 2, I have to generate a list of lists like this: 例如,如果我有x = 3和y = 2,我必须生成一个列表列表,如下所示:

[[1,1,1], [1,2,1], [2,1,1], [2,2,1], [1,1,2], [1,2,2], [2,1,2], [2,2,2]]

x and y are passed into the function and it has to work with any nonzero positive integers x and y. x和y被传递给函数,它必须使用任何非零正整数x和y。

I am completely lost and have no idea how to even begin. 我完全迷失了,不知道怎么开始。

For anyone kind enough to help me, please try to keep any math-heavy explanations as easy to understand as possible. 对于任何有兴趣帮助我的人,请尽量使用尽可能容易理解的数学解释。 I am really not good at math. 我真的不擅长数学。

Assuming that this is homework, I'll give you the part of the answer, and show you how I think through this sort of problem. 假设这是作业,我会给你答案的一部分,并告诉你我如何通过这类问题思考。 It's helpful to experiment in GHCi, and build up the pieces we need. 在GHCi中进行实验并构建我们需要的部分是有帮助的。 One thing we need is to be able to generate a list of numbers from 1 through y . 我们需要的一件事是能够生成从1到y的数字列表。 Suppose y is 7. Then: 假设y是7.那么:

λ> [1..7]
[1,2,3,4,5,6,7]

But as you'll see in a moment, what we really need is not a simple list, but a list of lists that we can build on. 但正如您稍后会看到的,我们真正需要的不是一个简单的列表,而是一个我们可以构建的列表列表。 Like this: 像这样:

λ> map (:[]) [1..7]
[[1],[2],[3],[4],[5],[6],[7]]

This basically says to take each element in the array, and prepend it to the empty list [] . 这基本上是指取数组中的每个元素,并将其添加到空列表[] So now we can write a function to do this for us. 所以现在我们可以编写一个函数来为我们这样做。

makeListOfLists y = map (:[]) [1..y]

Next, we need a way to prepend a new element to every element in a list of lists. 接下来,我们需要一种方法将新元素添加到列表列表中的每个元素。 Something like this: 像这样的东西:

λ> map (99:) [[1],[2],[3],[4],[5],[6],[7]]
[[99,1],[99,2],[99,3],[99,4],[99,5],[99,6],[99,7]]

(I used 99 here instead of, say, 1, so that you can easily see where the numbers come from.) So we could write a function to do that: (我在这里用的是99而不是1,所以你可以很容易地看到数字的来源。)所以我们可以编写一个函数来做到这一点:

prepend x yss = map (x:) yss

Ultimately, we want to be able to take a list and a list of lists, and invoke prepend on every element in the list to every element in the list of lists. 最终,我们希望能够获取列表和列表列表,并在列表中的每个元素上调用prepend列表中的每个元素。 We can do that using the map function again. 我们可以再次使用map函数。 But as it turns out, it will be a little easier to do that if we switch the order of the arguments to prepend , like this: 但事实证明,如果我们将参数的顺序切换为prepend将会更容易,如下所示:

prepend2 yss x = map (x:) yss

Then we can do something like this: 然后我们可以这样做:

λ>  map (prepend2 [[1],[2],[3],[4],[5],[6],[7]]) [97,98,99]
[[[97,1],[97,2],[97,3],[97,4],[97,5],[97,6],[97,7]],[[98,1],[98,2],[98,3],[98,4],[98,5],[98,6],[98,7]],[[99,1],[99,2],[99,3],[99,4],[99,5],[99,6],[99,7]]]

So now we can write that function: 所以现在我们可以编写该函数:

supermap xs yss = map (prepend2 yss) xs

Using your example, if x=2 and y=3, then the answer we need is: 使用您的示例,如果x = 2且y = 3,那么我们需要的答案是:

λ> let yss = makeListOfLists 3
λ> supermap [1..3] yss
[[[1,1],[1,2],[1,3]],[[2,1],[2,2],[2,3]],[[3,1],[3,2],[3,3]]]

(If that was all we needed, we could have done this more easily using a list comprehension. But since we need to be able to do this for an arbitrary x, a list comprehension won't work.) (如果这就是我们所需要的全部内容,我们可以使用列表理解更轻松地完成此操作。但由于我们需要能够为任意x执行此操作,因此列表理解不起作用。)

Hopefully you can take it from here, and extend it to arbitrary x. 希望您可以从这里获取它,并将其扩展到任意x。

For the specific x, as already mentioned, the list comprehension would do the trick, assuming that x equals 3, one would write the following: 对于特定的x,如前所述,列表理解可以解决问题,假设x等于3,可以编写以下内容:

 generate y = [[a,b,c] | a<-[1..y], b<-[1..y], c <-[1..y]]

But life gets much more complicated when x is not predetermined. 但是当x没有预先确定时,生活变得复杂得多。 I don't have much experience of programming in Haskell, I'm not acquainted with library functions and my approach is far from being the most efficient solution, so don't judge it too harshly. 我在Haskell中没有太多的编程经验,我不熟悉库函数,我的方法远不是最有效的解决方案,所以不要过于严厉地判断它。

My solution consists of two functions: 我的解决方案包括两个功能:

strip [] = []
strip (h:t) = h ++ strip t

populate y 2 = strip( map (\a-> map (:a:[]) [1..y]) [1..y])
populate y x = strip( map (\a-> map (:a) [1..y]) ( populate y ( x - 1) ))

strip is defined for the nested lists. strip是为嵌套列表定义的。 By merging the list-items it reduces the hierarchy so to speak. 通过合并列表项,它可以减少层次结构。 For example calling 例如打电话

strip [[1],[2],[3]]

generates the output: 生成输出:

[1,2,3]

populate is the tricky one. 填充是棘手的。

On the last step of the recursion, when the second argument equals to 2, the function maps each item of [1..y] with every element of the same list into a new list. 在递归的最后一步,当第二个参数等于2时,函数将[1..y]的每个项目与同一列表中的每个元素映射到一个新列表中。 For example 例如

map (\a-> map (:a:[]) [1..2]) [1..2])

generates the output: 生成输出:

[[[1,1],[2,1]],[[1,2],[2,2]]]

and the strip function turns it into: 并且条带功能将其转换为:

[[1,1],[2,1],[1,2],[2,2]]

As for the initial step of the recursion, when x is more than 2, populate does almost the same thing except this time it maps the items of the list with the list generated by the recursive call. 至于递归的初始步骤,当x大于2时,populate几乎完全相同,除了这次它将列表的项目与递归调用生成的列表进行映射。 And Finally: 最后:

populate 2 3

gives us the desired result: 给我们想要的结果:

[[1,1,1],[2,1,1],[1,2,1],[2,2,1],[1,1,2],[2,1,2],[1,2,2],[2,2,2]]

As I mentioned above, this approach is neither the most efficient nor the most readable one, but I think it solves the problem. 正如我上面提到的,这种方法既不是最有效也不是最可读的方法,但我认为它解决了这个问题。 In fact, theoritically the only way of solving this without the heavy usage of recursion would be building the string with list comprehension statement in it and than compiling that string dynamically, which, according to my short experience, as a programmer, is never a good solution. 实际上,理论上解决这个问题的唯一方法是在没有大量使用递归的情况下构建带有list comprehension语句的字符串,而不是动态编译该字符串,根据我的短暂经验,作为程序员,它永远不会是一个好的解。

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

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