patternpythonMinor
2D lattice random walk plots in functional style
Viewed 0 times
randomplotslatticestylewalkfunctional
Problem
To practice writing code in the functional programming style, I wrote a program to plot two-dimensional lattice random walks. I'd appreciate any feedback about how to improve its "functionaliness".
Call
EDIT
I have now compiled a far schnazier version as a shiny app:
Check it out!
Thanks for the help!
possibleSteps <- list(c(-1,0), c(0,-1), c(1,0), c(0,1))
step <- function(x) {
return(unlist(sample(possibleSteps, 1)))
}
takeRandomWalk <- function(nSteps) {
coordPairs <- Reduce(`+`, lapply(1:nSteps, step), accumulate = T)
x <- sapply(coordPairs, `[`, 1)
y <- sapply(coordPairs, `[`, 2)
return(list(x, y))
}
plotRandomWalk <- function(nSteps, margins) {
walkObj <- takeRandomWalk(nSteps)
plot(seq(-margins,margins), seq(-margins,margins),
type = 'n', xlab = "", ylab = "")
lines(walkObj[[1]], walkObj[[2]])
}Call
plotRandomWalk(10000, 80) for an example.EDIT
I have now compiled a far schnazier version as a shiny app:
Check it out!
Thanks for the help!
Solution
Looks good. The code is functional with the exception of using
anyway, so I'd simplify to the following and also in the interested of
efficiency only compute the
shorter:
time I've seen an
anywhere.
Now I think you know that, but usually R code like this would be written
with less lists and more data frames or matrixes. That doesn't mean the
code isn't functional: As long as it's using functions, not mutating
things and using functional abstractions instead of imperative
constructs it's fine.
So the following is probably more idiomatic and at the same time uses
more efficient representations for the data:
Gives a matrix with named columns like so, which will be the representation
throughout the rest of the code (which is good for consistency):
The random walk will still be created by
indexes.
(
And finally
return, which is not necessary as the last value will be returnedanyway, so I'd simplify to the following and also in the interested of
efficiency only compute the
coords once and without seq, as : isshorter:
step <- function(x) {
unlist(sample(possibleSteps, 1))
}
takeRandomWalk <- function(nSteps) {
coordPairs <- Reduce(`+`, lapply(1:nSteps, step), accumulate = T)
x <- sapply(coordPairs, `[`, 1)
y <- sapply(coordPairs, `[`, 2)
list(x, y)
}
plotRandomWalk <- function(nSteps, margins) {
walkObj <- takeRandomWalk(nSteps)
coords <- -margins:margins
plot(coords, coords, type = 'n', xlab = "", ylab = "")
lines(walkObj[[1]], walkObj[[2]])
}Reduce with accumulate is pretty cool, I think this is the firsttime I've seen an
accumulate parameter on a reduce-like functionanywhere.
Now I think you know that, but usually R code like this would be written
with less lists and more data frames or matrixes. That doesn't mean the
code isn't functional: As long as it's using functions, not mutating
things and using functional abstractions instead of imperative
constructs it's fine.
So the following is probably more idiomatic and at the same time uses
more efficient representations for the data:
possibleSteps <- matrix(c(-1, 0, 0, -1, 1, 0, 0, 1), ncol = 2, byrow = TRUE,
dimnames = list(NULL, c("X", "Y")))Gives a matrix with named columns like so, which will be the representation
throughout the rest of the code (which is good for consistency):
> possibleSteps
X Y
[1,] -1 0
[2,] 0 -1
[3,] 1 0
[4,] 0 1The random walk will still be created by
sample, except it's samplingindexes.
cbind will create a new matrix from the two accumulated sums(
cumsum):takeRandomWalk <- function(nSteps) {
indexes <- sample(1:dim(possibleSteps)[1], nSteps, TRUE)
walk <- possibleSteps[indexes,]
cbind(X = cumsum(walk[,1]), Y = cumsum(walk[,2]))
}And finally
plotRandomWalk is a bit simpler as we can just givelines the constructed coordinates matrix:plotRandomWalk <- function(nSteps, margins) {
coords <- -margins:margins
plot(coords, coords, type = 'n', xlab = "", ylab = "")
lines(takeRandomWalk(nSteps))
}Code Snippets
step <- function(x) {
unlist(sample(possibleSteps, 1))
}
takeRandomWalk <- function(nSteps) {
coordPairs <- Reduce(`+`, lapply(1:nSteps, step), accumulate = T)
x <- sapply(coordPairs, `[`, 1)
y <- sapply(coordPairs, `[`, 2)
list(x, y)
}
plotRandomWalk <- function(nSteps, margins) {
walkObj <- takeRandomWalk(nSteps)
coords <- -margins:margins
plot(coords, coords, type = 'n', xlab = "", ylab = "")
lines(walkObj[[1]], walkObj[[2]])
}possibleSteps <- matrix(c(-1, 0, 0, -1, 1, 0, 0, 1), ncol = 2, byrow = TRUE,
dimnames = list(NULL, c("X", "Y")))> possibleSteps
X Y
[1,] -1 0
[2,] 0 -1
[3,] 1 0
[4,] 0 1takeRandomWalk <- function(nSteps) {
indexes <- sample(1:dim(possibleSteps)[1], nSteps, TRUE)
walk <- possibleSteps[indexes,]
cbind(X = cumsum(walk[,1]), Y = cumsum(walk[,2]))
}plotRandomWalk <- function(nSteps, margins) {
coords <- -margins:margins
plot(coords, coords, type = 'n', xlab = "", ylab = "")
lines(takeRandomWalk(nSteps))
}Context
StackExchange Code Review Q#83460, answer score: 4
Revisions (0)
No revisions yet.