Scala - Automatic Iterator inside pattern match - scala

I have Array Data like this : [("Bob",5),("Andy",10),("Jim",7),...(x,y)].
How to do pattern matching in Scala? so they will match automatically based on Array Data that i have provided (instead of define "Case" one by one)
i mean dont like this, pseudocode :
val x = y.match {
case "Bob" => get and print Bob's Score
case "Andy" => get and print Andy's Score
..
}
but
val x = y.match {
case automatically defined by given Array => print each'score
}
Any Idea ? thanks in advance

If printing and storing results in an array is your main concern than the following will work well:
val ls = Array(("Bob",5),("Andy",10),("Jim",7))
ls.map({case (x,y) => println(y); y}) // print and store the score in an array

A bit confused about the question however if you just wish to print all the data in the array i would go about it doing this:
val list = Array(("Foo",3),("Tom",3))
list.foreach{
case (name,score) =>
println(s"$name scored $score")
}
//output:
//Foo scored 3
//Tom scored 3

Consider
val xs = Array( ("Bob",5),("Andy",10),("Jim",7) )
for ( (name,n) <- xs ) println(s"$name scores $n")
and also
xs.foreach { t => println(s"{t._1} scores ${t._2}") }
xs.foreach { t => println(t._1 + " scores " + t._2) }
xs.foreach(println)
A simple way to print the contents of xs,
println( xs.mkString(",") )
where mkString creates a string out of xs and separates each item by a comma.
Miscellany notes
To illustrate pattern matching on Scala Array, consider
val x = xs match {
case Array( t # ("Bob", _), _*) => println("xs starts with " + t._1)
case Array() => println("xs is empty")
case _ => println("xs does not start with Bob")
}
In the first case we extract the first tuple, and neglect the rest. In the first tuple we match against string "Bob" and neglect the second item. Moreover, we bind the first tuple to tag t, which is used in the printing where we refer to its first item.
The second case means every other case not covered.

Related

How to create listBuffer in collect function

I tought that List is enough but I need to add element to my list.
I've tried to put this in ListBuffer constructor but without result.
var leavesValues: ListBuffer[Double] =
leaves
.collect { case leaf: Leaf => leaf.value.toDouble }
.toList
Later on I'm going to add value to my list so my expected output is mutable list.
Solution of Raman Mishra
But what if I need to append single value to the end of leavesValues
I can reverse but it's not good enough
I can use ListBuffer like below but I believe that there is cleaner solution:
val leavesValues: ListBuffer[Double] = ListBuffer()
leavesValues.appendAll(leaves
.collect { case leaf: Leaf => leaf.value.toDouble }
.toList)
case class Leaf(value:String)
val leaves = List(Leaf("5"), Leaf("6"), Leaf("7"), Leaf("8") ,Leaf("9") )
val leavesValues: List[Double] =
leaves
.collect { case leaf: Leaf => leaf.value.toDouble }
val value = Leaf("10").value.toDouble
val answer = value :: leavesValues
println(answer)
you can do it like this after getting the list of leavesValues you can prepand the value you want to add into the list.

How can I emit periodic results over an iteration?

I might have something like this:
val found = source.toCharArray.foreach{ c =>
// Process char c
// Sometimes (e.g. on newline) I want to emit a result to be
// captured in 'found'. There may be 0 or more captured results.
}
This shows my intent. I want to iterate over some collection of things. Whenever the need arrises I want to "emit" a result to be captured in found. It's not a direct 1-for-1 like map. collect() is a "pull", applying a partial function over the collection. I want a "push" behavior, where I visit everything but push out something when needed.
Is there a pattern or collection method I'm missing that does this?
Apparently, you have a Collection[Thing], and you want to obtain a new Collection[Event] by emitting a Collection[Event] for each Thing. That is, you want a function
(Collection[Thing], Thing => Collection[Event]) => Collection[Event]
That's exactly what flatMap does.
You can write it down with nested fors where the second generator defines what "events" have to be "emitted" for each input from the source. For example:
val input = "a2ba4b"
val result = (for {
c <- input
emitted <- {
if (c == 'a') List('A')
else if (c.isDigit) List.fill(c.toString.toInt)('|')
else Nil
}
} yield emitted).mkString
println(result)
prints
A||A||||
because each 'a' emits an 'A', each digit emits the right amount of tally marks, and all other symbols are ignored.
There are several other ways to express the same thing, for example, the above expression could also be rewritten with an explicit flatMap and with a pattern match instead of if-else:
println(input.flatMap{
case 'a' => "A"
case d if d.isDigit => "|" * (d.toString.toInt)
case _ => ""
})
I think you are looking for a way to build a Stream for your condition. Streams are lazy and are computed only when required.
val sourceString = "sdfdsdsfssd\ndfgdfgd\nsdfsfsggdfg\ndsgsfgdfgdfg\nsdfsffdg\nersdff\n"
val sourceStream = sourceString.toCharArray.toStream
def foundStreamCreator( source: Stream[Char], emmitBoundaryFunction: Char => Boolean): Stream[String] = {
def loop(sourceStream: Stream[Char], collector: List[Char]): Stream[String] =
sourceStream.isEmpty match {
case true => collector.mkString.reverse #:: Stream.empty[String]
case false => {
val char = sourceStream.head
emmitBoundaryFunction(char) match {
case true =>
collector.mkString.reverse #:: loop(sourceStream.tail, List.empty[Char])
case false =>
loop(sourceStream.tail, char :: collector)
}
}
}
loop(source, List.empty[Char])
}
val foundStream = foundStreamCreator(sourceStream, c => c == '\n')
val foundIterator = foundStream.toIterator
foundIterator.next()
// res0: String = sdfdsdsfssd
foundIterator.next()
// res1: String = dfgdfgd
foundIterator.next()
// res2: String = sdfsfsggdfg
It looks like foldLeft to me:
val found = ((List.empty[String], "") /: source.toCharArray) {case ((agg, tmp), char) =>
if (char == '\n') (tmp :: agg, "") // <- emit
else (agg, tmp + char)
}._1
Where you keep collecting items in a temporary location and then emit it when you run into a character signifying something. Since I used List you'll have to reverse at the end if you want it in order.

Scala: AND conjunction in Lists

So I have result: List[List[Int]] = (List(0,1), List(0,1), List(1)) and I want to get the numbers every element of the the list has in common (in this case 1) like a logical AND conjunction. How can I do that?
Edit: If an element is empty it should return an empty List because there are no values every element has in common
Intuitive way
In each sublist, filter out the elements that are contained in all sublists, then flatten and remove duplicated:
val result1 = list.flatMap(_.filter(e => list.forall(_.contains(e)))).toSet
More efficient way
Find the smallest sublist and pick out elements that are in each sublist:
val result2 = list.minBy(_.size).filter(e => list.forall(_.contains(e))).toSet
Mathematical way
Turn each sublist into a set and intersect them:
val result3 = list.map(_.toSet).reduce(_.intersect(_))
You can do it with the intersect method:
def intersection(lists: List[List[Int]]): List[Int] = {
lists.headOption match {
case Some(head) =>
lists.foldLeft(head)((acc, l) => acc.intersect(l))
case None => Nil
}
The method may be more efficient if you use it with Set instead of List
The difficulty here is to do the intersect on the empty element, in this case Set.empty . to avoid this and solve the problem more functionally we can do this
def uniqueElements(reults:List[List[Int]]):Set[Int] = {
results match {
case head1::head2::tail => head1.toSet intersect head2.toSet intersect uniqueElements(tail)
case head::Nil => head.toSet
case Nil => Set.empty[Int]
}
}

How to exclude a string from parsed text file using Scala?

A sample text file looks like this:
Date: Nov 12, 2004
Support_Addresses: Support#microsoft.com, suport#yahoo.com,
google#gmail.com,
support#comcast.net
Notes: Need to renew support contracts for software and services.
Expected output is:
Nov 12, 2004
Support#microsoft.com, suport#yahoo.com, google#gmail.com, support#comcast.net
Need to renew support contracts for software and services.
Basically, I need to exclude the field titles from the lines, so things like “Date:” , “Support_Addresses: “ and “Notes: “ are removed from the lines before they are saved to a CSV file. I have this code from other projects:
val support_agreements = lines
.dropWhile(line => !line.startsWith("Support_Addresses: "))
.takeWhile(line => !line.startsWith(“Notes: "))
.flatMap(_.split(","))
.map(_.trim())
.filter(_.nonEmpty)
.mkString(", ")
But it does not remove the field titles/names. I am using startsWith, but it includes the field name. How can I exclude the field name from the line?
This should do it:
text.lines.map{ line =>
line.indexOf(':') match {
case x if x > 0 =>
line.substring(x + 1).trim
case _ => line.trim
}
}.mkString("\n")
it iterates through the lines and if it finds a colon it calls the substring function
Here's what I came up with. It builds a map of data m which could be manipulated usefully. This is then printed in the form you wanted.
def processValue(s: String): List[String] =
s.split(",").toList.map(_.trim).filterNot(_.isEmpty)
val retros = lines.foldLeft(List.empty[(String, List[String])]) {
case (acc, l) =>
l.indexOf(':') match {
case -1 =>
acc match {
case Nil => acc // ???
case h :: t => (h._1, h._2 ++ processValue(l)) :: t
}
case n =>
val key = l.substring(0, n).trim
val value = processValue(l.substring(n+1))
(key, value) :: acc
}
}
val m = retros.reverse.toMap
m.values.map(_.mkString(", ")).foreach(println)

Scala zipWithIndex over a sequence of Strings, do something different with last entry

I have a Seq[String] the represent a file, every String is a line in the file.
I'm iterating over the lines and parsing the record:
fileLines.zipWithIndex.foreach {
case(fileLine, filePosition) => parseRecord(fileLine, filePosition)
}
Now, for the last record I need to do a different parsing. Let's say parseLastRecord(). What is the best Scala-way to do it?
The main reason for my question is that it would be totally fine to do the last line parsing inside parseRecord that I already use, but, I don't want to pass the filePosition+totalSize into it...
While pattern matching you can check the index and call whichever function you want to call from there.
eg. if last element I'm printing something otherwise each element in following example.
List(1, 2, 3, 4).zipWithIndex.foreach{
case (element, index) if index == 3 => println("last element")
case (element, index) => println(element)
}
output
1
2
3
last element
So, your case would be something as below,
fileLines.zipWithIndex.foreach {
case(fileLine, filePosition) if filePosition == fileLines.length-1 => parseLastRecord(fileLine, filePosition)
case(fileLine, filePosition) => parseRecord(fileLine, filePosition)
}
using pattern matching
val l = List(1,2,3,4)
val spe = l.length - 1
l.zipWithIndex.foreach{ case(item, pos) => {pos match { case `spe` => println(s"$item $pos special"); case _ => println(s"$item $pos");}}}
in your case
val last = fileLines.length - 1
fileLines.zipWithIndex.foreach {
case(fileLine, filePosition) => {filePosition match {
case `last` => parseLastRecord(fileLine, filePosition)
case _ => parseRecord(fileLine, filePosition);
}