Scala foldLeft with a List - scala

I have the following code snippet:
import scala.io.Source
object test extends App {
val lineIterator = Source.fromFile("test1.txt").getLines()
val fileContent = lineIterator.foldLeft(List[String]())((list, currentLine) => {
currentLine :: list
list
})
fileContent foreach println
}
Let's assume the test1.txt file is not empty and has some values in it.
So my question about the foldLeft function is, why does this example here return an empty list, and when I remove the list at the end of the foldLeft function it works?
Why is it returning an empty list under the value fileContent?

The line currentLine :: list does not mutate the original list. It creates a new list with currentLine prepended, and returns that new list. When this expression is not the last one in your block, it will just be discarded, and the (still) empty list will be returned.
When you remove the list at the end, you will actually return currentLine :: list.

You call foldLeft with some start value (in your case an empty list) and a function, which takes an accumulator and the current value. This function returns the new list then. In your implementation the empty list from the first call will propagate to the end of function execution. This is why you get an empty list as a result.
Please look at this example: https://twitter.github.io/scala_school/collections.html#fold

list is immutable, so it is still empty after currentLine :: list. Thus the code within brackets returns an empty List, which is then folded with the next item, still returning an empty List.

Related

scala.collection.immutable.$colon$colon cannot be cast to java.lang.String

I am iterating with a map with key-value as
Map(fields -> List(
pangaea_customer_id, email_hash, savings_catcher_balance,
is_savings_catcher_member, billing_zipcode
))
I am trying below code to get the value of fields key
val fields = ValuesMap.get("fields")
But I am not able to convert fields to comma-separated String.
Please help me on how to do this.
I am trying with
val fields = ValuesMap.get("fields").mkString(",")
but it will return
List(pangaea_customer_id, email_hash, savings_catcher_balance,
is_savings_catcher_member, billing_zipcode)
get returns an Option[V] (because the key may be unmapped, and then it needs to return None).
Option can be iterated, just like a List, so you can call mkString on it, but it only ever returns at most one element, so the separator character will not be used.
Try getOrElse("fields", Seq.empty).mkString(",")
What your version did is:
get("fields") returns Some(List(....))
you call mkString on the Option, will will just give you either an empty String (if it was None), or (in your case), the result of toString for the element inside (which is the List as a whole).
You can try this:
val fields = res8.get("fields").getOrElse(List()).mkString(",")
// output: fields: String = pangaea_customer_id,email_hash,savings_catcher_balance,is_savings_catcher_member,billing_zipcode

Clarify the working of add and printNodes functions in this code

In this code I can able to understand the use of X for dynamic type casting. But I can't able to understand how add function really loads the data.
anyone please help me to understand step by step execution of add and printNodes method in detail. Thanks
class UsingGenericsForLinkedList[X] {
private class Node[X](elem: X) {
var next: Node[X] = _
override def toString = elem.toString
}
private var head: Node[X] = _
def add(elem: X) { //Add element in the linekd list
val value = new Node(elem)
value.next = head
head = value
}
private def printNodes(value: Node[X]) { // prining value of the nodes
if (value != null) {
println(value)
printNodes(value.next)
}
}
def printAll() { printNodes(head) } //print all the node values at a time
}
In a (singly) linked list, one maintains cells (here the Node class) that carry an element payload and a pointer to the next cell. Here you have a mutable linked list, so the next pointers can be updated (are mutable vars). The outer structure keeps a pointer to head, the first node of the list, which is initially null to indicate an empty list. When you traverse, you find the first node in head, then do something with its payload (the payload is elem in Node which is only made available here through toString), then repeat the procedure by looking at the next pointer, until that becomes null.
Note that add replaces head, and puts the previous value of head into the next field of the newly inserted node. So technically, this prepends an element to the list, it will become the first element to be found. So if you do add(1), add(2), add(3), you get the traversal 3, 2, 1. This is equivalent to :: in Scala's default List class.
Here is a tutorial on Scala's (immutable) List type; the only difference there is that you never replace next or head pointers, but return a new head cell when you prepend.

Scala: mutable HashMap does not update inside for loop

I have a var permutedTables = HashMap[List[Int], List[String, String]] defined globally. I first populate the Hashmap with the keys in a method, which works.
print(permutedTables) :
Map(List(1,2,3,4) -> List(),
List(2,4,5,6) -> List(), etc...)
The problem occurs when I want to update the values (empty lists) of the HashMap inside a for loop (inside a second method). In other words, I want to add tuples (String, String) in the List() for each key.
for(pi_k <- permutedTables.keySet){
var mask = emptyMask;
mask = pi_k.foldLeft(mask)((s, i) => s.updated(i, '1'))
val maskB = Integer.parseInt(mask,2)
val permutedFP = (intFP & maskB).toBinaryString
// attempt 1 :
// permutedTables(pi_k) :+ (url, permutedFP)
// attempt 2 :
// permutedTables.update(pi_k, permutedTables(pi_k):::List((url, permutedFP)))
}
The values do not update. I still have empty lists as values. I don't understand what is wrong with my code.
EDIT 1: When I call print(permutedTables) after any of the two attempts (inside the loop), the value seem updated, but when I call it outside of the loop, the Lists are empty
EDIT 2: The second attempt in my code seems to work now(!). But why does first not work ?
The second attempt in my code seems to work now(!). But why does first not work ?
Because what you do in the first case is get a list from permutedTables, add an element and throw away the result without storing it back. It would work if you mutated the value, but a List is immutable. With List, you need
permutedTables += pi_k -> permutedTables(pi_k) :+ (url, permutedFP)
Or, as you saw, update.
You can use e.g. ArrayBuffer or ListBuffer as your value type instead (note that you need :+= instead of :+ to mutate them), and convert to your desired type at the end. This is going to be rather more efficient than appending to the end of the list, unless the lists are quite small!
Finally, note that you generally want either var or a mutable type, not both at the same time.

Confused about appending to a List

I create a List like this :
var multiList : List[MyObj] = Nil
To append objects to this List I use :
multiList = multiList ::: List(MyObj)
this works but should I not be using
multiList = multiList ::: MyObj
as here I am appending an object to the List, wheras in example (that works) it looks syntactically as if im appending a new List to a List ?
The ::: operators mean concatenate, not append. There's :+ for element-append.
The :: method is used to 'prepend' stuff to a list. The ::: operator is used to prepend one list to another. The :: ends with a colon and thus is 'right associative' which can be explained as follows
x :: y
// will be translated to
y.::(x)
So to add your object to an empty list you could do
MyObj :: Nil
// will be translated to
Nil.::(MyObj)
If you wanted to add a list of objects to an empty list you could do
List(MyObj, MyObj) ::: Nil
// will be translated to
Nil.:::(List(MyObj, MyObj))
If you do want to append you could use the :+ method. This however performs differently for different types of collections. More info about the perfomance can be found here: Performance Characteristics

File I/O loop breaking prematurely?

I'm reading a file line by line using this loop:
for(line <- s.getLines()){
mylist += otherFunction(line);
}
where the variable mylist is a ArrayBuffer which stores a collection of custom datatypes. The otherFunction(line); does something like this...
def otherFunction(list:String)={
val line = s.getLine(index);
val t = new CustomType(0,1,line(0));
t
}
and CustomType is defined as...
class CustomType(name:String,id:Int,num:Int){}
I've ommitted much of the code as you can see because it's not relevant. I can run the rest of my functions and it'll read the file line by line till EOF as long as I comment out the last line of otherFunction(). Why is returning a value in this function to my list causing my for loop to stop?
It's not clear exactly what you're trying to do here. I assume s is a scala.io.Source object. Why does otherFunction take a string argument that it doesn't use? getLine is deprecated, and you don't say where index comes from. Do you really want to refer to the first character in the line String with index 0, and is it really supposed to be an Int? Assuming that this is actually what you want to do, why not just use a map on the iterator?
val list = s.getLines.map(i => new CustomType("0", 1, i(0).asDigit)).toIndexedSeq