Reordering Sequences in Scala - scala

I have a sequence with the following data order:
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O
and I need to sort it so that it looks like this:
A, F, K, B, G, L, C, H, M, D, I, N, E, J, O
which is basically grouping the first sequence in to three groups, stacking them on the top of each other and reading down the first column and then the next etc to form the new sequence.
ABCDE
FGHIJ
KLMNO
I have a conceptual understanding that this might involve mapping and zipping. I could implement this in short order in imperative style, but I want it as a functional style.
Any help/pointers gratefully received, thanks!

Here you go:
val xs = Seq('A, 'B, 'C, 'D, 'E, 'F, 'G, 'H, 'I, 'J, 'K, 'L, 'M, 'N, 'O)
val grouped = xs.grouped(5).toList
// List(List('A, 'B, 'C, 'D, 'E), List('F, 'G, 'H, 'I, 'J), List('K, 'L, 'M, 'N, 'O))
val result = grouped.transpose.flatten
// List('A, 'F, 'K, 'B, 'G, 'L, 'C, 'H, 'M, 'D, 'I, 'N, 'E, 'J, 'O)

Any solution should start out with grouped, which chops the collection into pieces:
scala> val g = "ABCDEFGHIJKLMN".grouped(5)
g: Iterator[String] = non-empty iterator // Will return "ABCDE", then "FGHIJ", then "KLMN"
We then turn everything into a list so we can take tails easily:
scala> val l = g.map(_.toList).toList
List[List[Char]] = List(List(A, B, C, D, E), List(F, G, H, I, J),
List(K, L, M, N))
Now we gather these by taking successive tails, stopping when there's nothing left:
scala> val i = Iterator.iterate(l)(_.map(_ drop 1).filter(_.nonEmpty)).takeWhile(_.nonEmpty)
i: Iterator[List[List[Char]]] = non-empty iterator
// List(List(A, B, C, D, E), List(F, G, H, I, J), List(K, L, M, N))
// List(List(B, C, D, E), List(G, H, I, J), List(L, M, N))
// List(List(C, D, E), List(H, I, J), List(M, N))
// List(List(D, E), List(I, J), List(N))
// List(List(E), List(J))
That looks big, but since we're using a List, the shorter lists share memory with the longer ones, so it's not a horrible O(n^2) explosion in size. But we really just want the heads, and we already filtered out everything empty, so we can just do it:
scala> val h = i.map(_.map(_.head))
h: Iterator[List[Char]] = non-empty iterator
// List(A, F, K)
// List(B, G, L)
// List(C, H, M)
// List(D, I, N)
// List(E, J)
and finally convert from an iterator to a strict collection and flatten:
scala> val ans = h.toList.flatten
ans: List[Char] = List(A, F, K, B, G, L, C, H, M, D, I, N, E, J)
(add mkString if you want a String back).
Note that the temporary variables are for clarity of explanation only. If you feel like writing it all on one line, you could. (It'd be a rather long line.)
(Also note that if you e.g. print out iterators, they get consumed.)
Here it is in one big swoop:
("ABCDEFGHIJKLMN".grouped(5).map(_.toList).toList match {
case l => Iterator.iterate(l)(_.map(_ drop 1).filter(_.nonEmpty)).takeWhile(_.nonEmpty)
}).map(_.map(_.head)).toList.flatten
but that's pretty opaque, so spreading things out to give room for comments is a good idea.

Related

Loop over a List getting an increasing number of elements each time

Let's say I have a list that looks like
{A, B, C, D, E}
And I want to loop over this list, getting an increasing number of elements each time, so each iteration would look like:
Iteration 1: {A}
Iteration 2: {A, B}
Iteration 3: {A, B, C}
Iteration 4: {A, B, C, D}
Iteration 5: {A, B, C, D, E}
Currently I am accomplishing this with:
(1 to list.size).foreach( n => {
val elements = list.take(n)
// Do something with elements
})
But that feels messy. Is there a more 'scala' way of accomplishing this behavior?
You could use list.inits :
scala> List(1,2,3,4,5).inits.foreach(println)
List(1, 2, 3, 4, 5)
List(1, 2, 3, 4)
List(1, 2, 3)
List(1, 2)
List(1)
List()
To get your desired out put you would need to create a list from the iterator, reverse it and take the tail to omit the empty list:
scala> List(1,2,3,4,5).inits.toList.reverse.tail.foreach(println)
List(1)
List(1, 2)
List(1, 2, 3)
List(1, 2, 3, 4)
List(1, 2, 3, 4, 5)
You can use foldLeft with a linked list to accumulate the elements.
However, this will reverse the order, so you'll need to call the .reverse function if you really care about the order, which wouldn't be efficient.
list.foldLeft(Nil : List[String]){(l, n) => {
val elements = n :: l
println(elements)
elements
}}
Output:
List(A)
List(B, A)
List(C, B, A)
List(D, C, B, A)
List(E, D, C, B, A)
Here's a version that preserves order but uses a ListBuffer, which isn't great
val elems = ListBuffer[String]()
list.foreach{ s =>
elems += s
println(elems)
}
The same, but with a fold
list.foldLeft(ListBuffer[String]()){(elems, s) =>
elems += s
println(elems)
elems
}
Output:
ListBuffer(A)
ListBuffer(A, B)
ListBuffer(A, B, C)
ListBuffer(A, B, C, D)
ListBuffer(A, B, C, D, E)
Here is a recursive version. You will need to reverse the list first.
#tailrec
def doIt(l: List[Int], acc: List[List[Int]] = Nil): List[List[Int]] = l match {
case Nil => acc
case h :: t => doIt(t, List(h) :: acc.map(l => h :: l))
}
doIt(List(1,2,3).reverse).foreach(println)
// output
List(1)
List(1, 2)
List(1, 2, 3)

Scala Random String

Hope you are doing good, I just started scala basic programming, I want to generate some string variable with foreach or something else you think is the best method.
How do I use scala.util.Random to generate this result:
Var 1A:String = random between A to J
Var 1B:String = random between A to J but not 1A value
Var 1C:String = random between A to J, not 1A and not 1B
Var 1D to 1J also should have different random value from A to J
So basically from 1A to 1J could be like this:
Var 1A = "B"
Var 1B = "G"
Var 1C = "A"
Var 1D = "D"
Var 1E = "H"
and so on until 1J
The simplest way is probably to use Random.shuffle.
First construct your list of characters:
scala> val chars = ('A' to 'J').toList
chars: List[Char] = List(A, B, C, D, E, F, G, H, I, J)
Then shuffle them:
scala> val shuffled = scala.util.Random.shuffle(chars)
shuffled: List[Char] = List(C, E, G, B, J, A, F, H, D, I)
Now you've got a list of these ten characters in a random order. If you need variables referring to them, you can do something like this:
scala> val List(a, b, c, d, e, f, g, h, i, j) = shuffled
a: Char = C
b: Char = E
c: Char = G
d: Char = B
e: Char = J
f: Char = A
g: Char = F
h: Char = H
i: Char = D
j: Char = I
(Note that 1A isn't a valid Scala identifier, and Val isn't valid syntax.)
Or you can refer to them by index:
val a = shuffled(0)
val b = shuffled(1)
...
Or you could just work with them in the list.
You can use shuffle from Random package:
scala> scala.util.Random.shuffle(('A' to 'J').toList map (_.toString))
res2: List[String] = List(C, F, D, E, G, A, B, I, H, J)
Assign the result to the list of variables if you like.

scala partial string match

I have a question about List of Strings partial Matching to a List of Strings (intersect I guess).
List1:List = [a,b,c,d,e,f]
List2:Iterable[String] = [a b,e f,g h,x y]
I want to take any element or combination of elements in List1 that also happens to be in List2, and replace it with the element in List2, for example, [a,b] are in List1, List 2 contains element [a b], in this case, [a,b] in List1 will be replaced with [a b]. The result for List 1 should be:
List1result = [a b,c,d,e f]
I've tried intersect, which would return [a b, e f]
Ok, I edited my answer after the comment bellow, I think I understood the question now.
take each element of the second list, convert it into a list of elements and use containsSlice to filter out the value.
containsSlice will return true if all the elements in the slice are present in the first list.
val lst1 = List("a","b","c","d","e","f")
val lst2 = List("a b","e f","g h","x y")
lst2.filter{ pair =>
val xss = pair.split(" ")
lst1.containsSlice(xss)
}
You can try something like this :
val l1 = List("a", "b", "c", "d", "e", "f")
val l2 = List("a b", "e f", "g h", "x y")
l1.filterNot(x=>l2.flatten.filter(_ != ' ').contains(x.toCharArray.head))
l2.foldLeft(List[String]()) { case (x, y) => if (l1.containsSlice(y.split(" "))) x :+ y else x} ++
l1.filterNot(x=>l2.flatten.filter(_ != ' ').contains(x.toCharArray.head))
l1: List[String] = List(a, b, c, d, e, f)
l2: List[String] = List(a b, e f, g h, x y)
res0: List[String] = List(a b, e f, c, d)

scala - String split("|") works incorrectly?

I've encountered a strange question on scala String split
here is my code:
scala> val s1 = "oauth_token=FOO&oauth_token_secret=BAR&oauth_expires_in=3600"
s1: String = oauth_token=FOO&oauth_token_secret=BAR&oauth_expires_in=3600
scala> s1.split("&")
res3: Array[String] = Array(oauth_token=FOO, oauth_token_secret=BAR, oauth_expires_in=3600)
so far, the split method works well, but..
scala> val s2 = "oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600"
s2: String = oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600
scala> s2.split("|")
res4: Array[String] = Array("", o, a, u, t, h, _, t, o, k, e, n, =, F, O, O, |, o, a, u, t, h, _, t, o, k, e, n, _, s, e, c, r, e, t, =, B, A, R, |, o, a, u, t, h, _, e, x, p, i, r, e, s, _, i, n, =, 3, 6, 0, 0)
the method actually splits out every character, even strangely, an empty string appears at the front.
I have tried other delimiters such as %, ,, the method still works well. It seems that split does not work correctly when | serve as delimiter?
split() expects a regular expression, and in regex-land | means "OR", so you're splitting on the empty string OR on the empty string, which is what you're seeing.
You can use an escape to split on literal |s:
scala> val s2 = "oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600"
s2: String = oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600
scala> s2.split("\\|")
res0: Array[String] = Array(oauth_token=FOO, oauth_token_secret=BAR, oauth_expires_in=3600)
Scala has an implicit conversion which provides split() method on strings that accepts char:
scala> val s2 = "oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600"
s2: String = oauth_token=FOO|oauth_token_secret=BAR|oauth_expires_in=3600
scala> s2.split('|')
res0: Array[String] = Array(oauth_token=FOO, oauth_token_secret=BAR, oauth_expires_in=3600)
Naturally, this only works if your splitter is a single character. If it is a multi-character string, you need to keep track of regex-specific characters yourself.

Scala's tuple unwrapping nuance

I've noticed the following behavior in scala when trying to unwrap tuples into vals:
scala> val (A, B, C) = (1, 2, 3)
<console>:5: error: not found: value A
val (A, B, C) = (1, 2, 3)
^
<console>:5: error: not found: value B
val (A, B, C) = (1, 2, 3)
^
<console>:5: error: not found: value C
val (A, B, C) = (1, 2, 3)
^
scala> val (u, v, w) = (1, 2, 3)
u: Int = 1
v: Int = 2
w: Int = 3
Is that because scala's pattern matching mechanism automatically presumes that all identifiers starting with capitals within patterns are constants, or is that due to some other reason?
Thanks!
Yes, and it gets worse:
val (i, j) : (Int, Int) = "Hello" -> "World"
The above will compile and fail at runtime with a ClassCastException. It is easy to forget that the (i, j) declaration is a pattern.
EDIT: for ziggystar, the Scala assignment rules state that in the statement:
val p = expr //or var
p can be either an identifier or a pattern (see section 15.7 of Programming in Scala, pp284). So for example, the following is valid:
val x :: y :: z :: rest = List(1, 2, 3, 4)
Taking this together with the fact that patterns are erased (i.e. parametric type information is unchecked) means that my original example will compile.
From [scala] Question about naming conventions you can read
The initial capital letter has an advantage when pattern matching. Identifiers with an initial capital letter are considered to be values to match against instead of a variable to be bound.
A workaround exists if you need to initialize a large number of constants and want to avoid writing val = for each or you are hitting the tuple size limit (22).
From section 4.1 of The Scala Language Specification:
A value definition val x: T = e defines x as a name of the value that
results from the evaluation of e. A value definition val p1, ..., pn =
e is a shorthand for the sequence of value definitions val p1 = e; ...;
val pn = e.
Per the specification, one can initialize a sequence of values all with names starting with capital letters by specifying an expression on the right-hand which returns each value in order.
val iter = Iterator(1, 2, 3)
val A, B, C = iter.next()
Another example:
val next = { var n = 0; () => { n = n + 1; n } }
val A, B, C, D, E, F, G, H = next()
In these trivial cases above this approach is not very useful. Below is a more useful example that initializes a constant for each of the 64 squares of the chessboard (see Square.scala#L31 for source):
val squareIter = squares.iterator
val A1, A2, A3, A4, A5, A6, A7, A8,
B1, B2, B3, B4, B5, B6, B7, B8,
C1, C2, C3, C4, C5, C6, C7, C8,
D1, D2, D3, D4, D5, D6, D7, D8,
E1, E2, E3, E4, E5, E6, E7, E8,
F1, F2, F3, F4, F5, F6, F7, F8,
G1, G2, G3, G4, G5, G6, G7, G8,
H1, H2, H3, H4, H5, H6, H7, H8 = squareIter.next()