Nested iteration in Scala - scala

What is the difference (if any) between two code fragments below?
Example from Ch7 of Programming i Scala
def grep(pattern: String) =
for (
file <- filesHere
if file.getName.endsWith(".scala");
line <- fileLines(file)
if line.trim.matches(pattern)
) println(file + ": " + line.trim)
and this one
def grep2(pattern: String) =
for (
file <- filesHere
if file.getName.endsWith(".scala")
) for (
line <- fileLines(file)
if line.trim.matches(pattern)
) println(file + ": " + line.trim)
Or
for (i <- 1 to 2)
for (j <- 1 to 2)
println(i, j)
and
for (
i <- 1 to 2;
j <- 1 to 2
) println(i, j)

In this case there is no difference. However when using yield there is:
for (
i <- 1 to 2;
j <- 1 to 2
) yield (i, j)
Will give you a sequence containing (1,1), (1,2), (2,1) and (2,2).
for (i <- 1 to 2)
for (j <- 1 to 2)
yield (i, j)
Will give you nothing, because it generates the sequence (i,1), (i,2) on each iteration and then throws it away.

Sometimes it is also useful to output a multi dimensional collection (for example a matrix of table):
for (i <- 1 to 2) yield for (j <- 1 to 2) yield (i, j)
Will return:
Vector(Vector((1,1), (1,2)), Vector((2,1), (2,2)))

Related

R2WinBUGS error (no prior specified for this initial value)

The original WinBUGS code is as follows:
model { for (i in 1:n) {for (j in 1:J) {y[i,j] <- equals(D[i],j)
D[i] ~ dcat(p[i,])
p[i,j] <- phi[i,j] / sum(phi[i,])
LL[i,j] <- y[i,j]*log(p[i,j])}
for (j in 2:J) {
S.ed[i,j] <- c1[j]*ed.c[i]+equals(degree,2)*c2[j]*ed.c[i]*ed.c[i]+inprod(delta.c[j,],Spline[i,])
log(phi[i,j]) <- beta0[j] + beta1[j]*white[i] + beta2[j]*exp.c[i] + S.ed[i,j]}
LLt[i] <- sum(LL[i,])
phi[i,1] <- 1
H[i] <- 1/exp(LLt[i])
exp.c[i] <- exp[i]-mean(exp[])
ed.c[i] <- ed[i]-mean(ed[])}
# Priors
beta0[1] <- 0; beta1[1] <- 0; beta2[1] <- 0; c1[1] <- 0; c2[1] <- 0
for (j in 2:J) {beta1[j] ~ dnorm(0,0.0001)
beta2[j] ~ dnorm(0,0.0001)
c1[j] ~ dnorm(0,0.0001)
c2[j] ~ dnorm(0,0.0001)
beta0[j] ~ dnorm(0,0.0001)}
Dv <- -2*sum(LLt[])
for (k in 1:K) {knot.c[k] <- knot[k]-mean(ed[])
# degree =1 for linear spline, =2 for quadratic spline
for (i in 1:337) { S[i,k] <- (ed.c[i]-knot.c[k])*step(ed[i]-knot[k])
Spline[i,k] <- pow(S[i,k],degree)}}
# Random spline coefficients
for (j in 2:J) {for (k in 1:K) {delta[j,k] ~ dnorm(0,tau[j]); delta.c[j,k] <- delta[j,k]-mean(delta[j,])}
# full conditionals for spline precision
tau[j] ~ dgamma(As[j],Bs[j]); As[j] <- 0.1 + K/2; Bs[j] <- 0.1 + inprod(delta.c[j,],delta.c[j,])/2}}
*INITIS*
list(beta1=c(NA,0,0,0,0),beta2=c(NA,0,0,0,0),c1=c(NA,0,0,0,0),
c2=c(NA,0,0,0,0),tau=c(NA,1,1,1,1),
beta0=c(NA,0,0,0,0),delta=structure(.Data=c(NA,NA,NA,NA,NA,NA,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),.Dim=c(5,6)))
list(beta1=c(NA,-0.5,0.5,0,0),beta2=c(NA,-0.5,0.5,0,0),
c1=c(NA,-0.5,0.5,0,0),c2=c(NA,-0.5,0.5,0,0),tau=c(NA,1,1,1,1),
beta0=c(NA,-0.5,0.5,0,0),delta=structure(.Data=c(NA,NA,NA,NA,NA,NA,
-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,
0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,0,0),.Dim=c(5,6)))
*DATA*
my own R2WinBUGS code is like this.
rm(list=ls())
setwd("C:/Users/~~/BMCD")
Data <- read.table("model604data.txt")
D<-Data[,1]; exp<-Data[,2]; ed<-Data[,3]; white<-Data[,4]; J=5; K=6; n=337; knot=c(9.6,12,13.6,14,16,16.4); degree=2;
data <- list(D=D, exp=exp, ed=ed, white=white, J=J, K=K, n=n, knot=knot, degree=degree)
parameters <- c("beta0","beta1","beta2")
inits =list(list(beta1=c(NA,0,0,0,0),beta2=c(NA,0,0,0,0),c1=c(NA,0,0,0,0),c2=c(NA,0,0,0,0),tau=c(NA,1,1,1,1),beta0=c(NA,0,0,0,0),delta=structure(.Data=c(NA,NA,NA,NA,NA,NA,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),.Dim=c(5,6))),
list(beta1=c(NA,-0.5,0.5,0,0),beta2=c(NA,-0.5,0.5,0,0),c1=c(NA,-0.5,0.5,0,0),c2=c(NA,-0.5,0.5,0,0),tau=c(NA,1,1,1,1),beta0=c(NA,-0.5,0.5,0,0),delta=structure(.Data=c(NA,NA,NA,NA,NA,NA,
-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,-0.5,0.5,0,0),.Dim=c(5,6))) )
model604 <- bugs(data, inits, parameters,model.file="C:/Users/~~/model604.odc",
debug=TRUE,n.chains=2, n.iter=2000, n.burnin=500, bugs.directory="C:/Program Files/WinBUGS14/" )'
How can I fix this error?
I tried to change NA in inits to 0, but it didn't work and give me another error message.
The data follows rectangular format but it's alright
the syntax translation for model and data will be okay, I guess.
Should I add the prior condition?

Acting on inner and outer loops for multidimensional array in idiomatic scala

I have this nested loop:
for ( y <- 0 to 5) {
for ( x <- 0 to 5) {
print(x, y)
}
println()
}
Is there a cleaner way of expressing this in scala -- bearing in mind I want to do something once for every outer loop iteration, as well as the internal?
The following is the closest I've got:
for {
y <- 0 to 5
x <- 0 to 5
} {
print (x, y) + " "
if(x == 5) println()
}
for {
y <- 0 to 5
x <- 0 to 5
_ = if (x ==5) println()
} print(x, y)
Seems like the most concise way to me.
I don't think for comprehensions are a good option here, why not just use foreach? like this:
(0 to 5).foreach{ y =>
(0 to 5).foreach{ x =>
print (x, y) + " "
}
println()
}

Scala loops with multiple conditions - what gets returned?

I'm going through scala for the impatient and came across an example of the multi condition loops that I can't seem to understand.
Coming from Java background I'm looking at these loops as nested for loops. But why does the first return a collection and second a String?
scala> for (i <- 0 to 1; c <- "Hello") yield (i + c).toChar
res11: scala.collection.immutable.IndexedSeq[Char] = Vector(H, e, l, l, o, I, f, m, m, p)
scala> for (c <- "Hello"; i <- 0 to 1) yield (i + c).toChar
res12: String = HIeflmlmop
for comprehensions are just syntax sugar and are translated into invocations of map, flatMap, withFilter (also foreach if you don't use yield).
for {
i <- 0 to 1
c <- "Hello"
} yield (i + c).toChar
is equivalent to
(0 to 1).flatMap(i => "Hello".map(c => (i + c).toChar))
These transformers are defined in a way that they return the same type of collection they were called on, or the closest one, for example here Range becomes a Vector in the end as you can't have Range that contains arbitrary characters. Starting from String you still can have String back.
In general you can think of it like this: result type created by for comprehension will be same as the type of the first generator (or closest possible).
For example if you convert string into a Set
for {
c <- "Hello".toSet[Char]
i <- 0 to 1
} yield (i + c).toChar
you will get a Set back, and because it is a set it will not contain duplicates so the result is different. Set(e, f, m, I, l, p, H, o)
The way how type is determined involves the CanBuildFrom trait. You can read more about how it works here
Use scala 2.11.8 repl for desugar (press tab after print, remove<pressed TAB here>):
scala> for (i <- 0 to 1; c <- "Hello") yield (i + c).toChar //print<pressed TAB here>
scala.Predef.intWrapper(0).to(1).flatMap[Char, scala.collection.immutable.IndexedSeq[Char]](((i: Int) =>
scala.Predef.augmentString(scala.Predef.augmentString("Hello").
map[Char, String](((c: Char) => i.+(c).toChar))(scala.Predef.StringCanBuildFrom))))(scala.collection.immutable.IndexedSeq.canBuildFrom[Char]) // : scala.collection.immutable.IndexedSeq[Char]
scala> for (i <- 0 to 1; c <- "Hello") yield (i + c).toChar //print
res4: scala.collection.immutable.IndexedSeq[Char] = Vector(H, e, l, l, o, I, f, m, m, p)
scala> for (c <- "Hello"; i <- 0 to 1) yield (i + c).toChar //print<pressed TAB here>
scala.Predef.augmentString("Hello").flatMap[Char, String](((c: Char) => scala.Predef.intWrapper(0).to(1).
map[Char, scala.collection.immutable.IndexedSeq[Char]](((i: Int) => i.+(c).toChar))(scala.collection.immutable.IndexedSeq.canBuildFrom[Char])))(scala.Predef.StringCanBuildFrom) // : String
scala> for (c <- "Hello"; i <- 0 to 1) yield (i + c).toChar //print
res5: String = HIeflmlmop
More readable output:
scala> (0 to 1).flatMap(i => "Hello".map(c => (i+c).toChar))
res14: scala.collection.immutable.IndexedSeq[Char] = Vector(H, e, l, l, o, I, f, m, m, p)
scala> "Hello".flatMap(c => (0 to 1).map(i => (i + c).toChar))
res15: String = HIeflmlmop

Exit for loop as soon as condition satisfied

The following code hangs the repl:
(
for {
i <- 1 to 1000000
j <- 2 to 1000000
if i * i == j
} yield i -> j
).take(1)
It seems the for expression is eagerly evaluated. Any solutions?
I'd turn that into a stream:
(
for {
i <- Stream.range(1, 1000000)
j <- Stream.range(2, 1000000)
if i * i == j
} yield i -> j
).take(1)

How does yield expand to in multiple dimension loop in Scala?

From Here we get to know that an expression like:
for( i <- 1 to 10 ) yield i + 1
will expand into
( 1 to 10 ).map( _+1 )
But what does the following expression expand to?
for( i <- 1 to 50 j <- i to 50 ) yield List(1,i,j)
Is this correct?
( 1 to 50 ).map( x => (1 to 50 ).map(List(1,x,_))
I'm interested in this problem because I'd like to make a function which performs multiple Xi <- Xi-1 to 50 operations, as shown below:
for( X1 <- 1 to 50 X2 <- X1 to 50 X3 <- X2 to 50 ..... Xn <- Xn-1 to 50 )
yield List(1,X1,X2,X3,.....,Xn)
The function has one parameter: dimension which denotes the n in the above expression.
Its return type is IndexSeq[List[Int]]
How can I achieve that?
Thank you for answering (:
It's well explained in a relevant doc. In particular:
for(x <- c1; y <- c2; z <- c3) yield {...}
will be translated into
c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
I don't think there is a way to abstract over arbitrary nested comprehension (unless you're using voodoo magic, like macros)
See om-nom-nom's answer for an explanation of what the for loops expand to. I'd like to answer the second part of the opening question, how to implement a function that can do:
for( X1 <- 1 to 50 X2 <- X1 to 50 X3 <- X2 to 50 ..... Xn <- Xn to 50 )
yield List(1,X1,X2,X3,.....,Xn)
You can use:
def upto50(dimension: Int) = {
def loop(n: Int, start: Int): IndexedSeq[List[Int]] = {
if (n > dimension)
IndexedSeq(List())
else {
(n to 50).flatMap(x => loop(n + 1, x).map(x :: _))
}
}
loop(1, 1)
}
We compute each of the loops recursively, working inside-out, starting with Xn to 50 and building up the solution.
Solutions for the more general case of:
for( X1 <- S1 X2 <- S2 X3 <- S3 ..... Xn <- Sn )
yield List(1,X1,X2,X3,.....,Xn)
Where S1..Sn are arbitraray sequences or monads are also possible. See this gist for the necessary wall of code.