How can I add a blank line before some data using Ruamel.yaml - ruamel.yaml

I can't seem to figure out how I can add a blank line between data using Ruamel.yaml.
Suppose I have data:
---
a: 1
b: 2
I need to add to this so that I will have:
---
a: 1
b: 2
c: 3
I understand that the blank line is implemented as a CommentToken:
Comment(comment=None,
items={'data': [None, None, CommentToken(value=u'\n\n'), None], 'b': [None, None, CommentToken(value=u'\n\n'), None]})
What I don't know is how to manipulate that structure.

That Comment object is not from the input that you give, as data is not a key in your mapping, that should be a:
import ruamel.yaml
yaml_strs = [
"""\
---
a: 1
b: 2
""",
"""\
---
a: 1
b: 2
c: 3
"""]
for yaml_str in yaml_strs:
data = ruamel.yaml.round_trip_load(yaml_str)
print(data.ca)
gives:
Comment(comment=None,
items={'a': [None, None, CommentToken(), None]})
Comment(comment=None,
items={'a': [None, None, CommentToken(), None], 'b': [None, None, CommentToken(), None]})
comparing the above comments should give you an idea of what to try:
import sys
import ruamel.yaml
yaml_str = """\
---
a: 1
b: 2
"""
data = ruamel.yaml.round_trip_load(yaml_str)
data['c'] = 3
ct = data.ca.items['a'][2]
data.ca.items['b'] = [None, None, ct, None]
ruamel.yaml.round_trip_dump(data, sys.stdout)
which gives:
a: 1
b: 2
c: 3
The CommentToken ct can also be constructed from scratch:
ct = ruamel.yaml.tokens.CommentToken('\n\n', ruamel.yaml.error.CommentMark(0), None)
as is, e.g. done in ruamel.yaml.comments.CommentedBase.yaml_set_start_comment().
The 0 parameter to CommentMark() is how far the comment is indented, which is not important in case of empty lines, but still needs to be provided.

Related

How to split one liner object keys to multiple lines - so each key will has its own line?

I have this:
method({ a: 1, b: 2, c: 3 });
I want to find the magic key in VSCode that turns it to this:
method({
a: 1,
b: 2,
c: 3
});
And vice versa

How to find duplicates in a list in Scala?

I have a list of unsorted integers and I want to find the elements which are duplicated.
val dup = List(1|1|1|2|3|4|5|5|6|100|101|101|102)
I have to find the list of unique elements and also how many times each element is repeated.
I know I can find it with below code :
val ans2 = dup.groupBy(identity).map(t => (t._1, t._2.size))
But I am not able to split the above list on "|" . I tried converting to a String then using split but I got the result below:
L
i
s
t
(
1
0
3
)
I am not sure why I am getting this result.
Reference: How to find duplicates in a list?
The symbol | is a function in scala. You can check the API here
|(x: Int): Int
Returns the bitwise OR of this value and x.
So you don't have a List, you have a single Integer (103) which is the result of operating | with all the integers in your pretended List.
Your code is fine, if you want to make a proper List you should separate its elements by commas
val dup = List(1,1,1,2,3,4,5,5,6,100,101,101,102)
If you want to convert your given String before having it on a List you can do:
"1|1|1|2|3|4|5|5|6|100|101|101|102".split("\\|").toList
Even easier, convert the list of duplicates into a set - a set is a data structure that by default does not have any duplicates.
scala> val dup = List(1,1,1,2,3,4,5,5,6,100,101,101,102)
dup: List[Int] = List(1, 1, 1, 2, 3, 4, 5, 5, 6, 100, 101, 101, 102)
scala> val noDup = dup.toSet
res0: scala.collection.immutable.Set[Int] = Set(101, 5, 1, 6, 102, 2, 3, 4, 100)
To count the elements, just call the method sizeon the resulting set:
scala> noDup.size
res3: Int = 9
Another way to solve the problem
"1|1|1|2|3|4|5|5|6|100|101|101|102".split("\|").groupBy(x => x).mapValues(_.size)
res0: scala.collection.immutable.Map[String,Int] = Map(100 -> 1, 4 -> 1, 5 -> 2, 6 -> 1, 1 -> 3, 102 -> 1, 2 -> 1, 101 -> 2, 3 -> 1)

Significance of val or var in immutable objects

Does val or var make difference in immutable objects like lists or tuple?
scala> val ab = List(1,2,3)
ab: List[Int] = List(1, 2, 3)
scala> var ab = List(1,2,3)
ab: List[Int] = List(1, 2, 3)
I am beginner in scala.
You may be confusing two different aspects of immutability. The local variable ab refers to some object in memory, in this case a List. When you declare ab as a val you are instructing the compiler that ab will always refer to the same object. Because List is immutable, its contents will never change, but a var referring to it might be reassigned to some other List.
scala> import scala.collection.mutable.MutableList
import scala.collection.mutable.MutableList
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
scala> val b = MutableList(1,2,3,4)
b: scala.collection.mutable.MutableList[Int] = MutableList(1, 2, 3, 4)
scala> var c = List(1,2,3,4)
c: List[Int] = List(1, 2, 3, 4)
Here, a is a val containing an immutable data structure. a refers to List(1,2,3,4) and will always do so.
The val b refers to a MutableList. We can change the internal contents of the MutableList but we cannot assign b to a different MutableList.
scala> b += 5
res6: b.type = MutableList(1, 2, 3, 4, 5)
scala> b = MutableList(2,3,5,7)
<console>:12: error: reassignment to val
b = MutableList(2,3,5,7)
^
With var c we have a variable that refers to an immutable data structure List but that can be reassigned to a different List.
scala> c = c :+ 5
c: List[Int] = List(1, 2, 3, 4, 5)
Note that the :+ operator (unlike the += operator above) does not change the List referred to by c. Instead it create a copy of the List with the element 5 appended. Because c was declared a var we can then assign this new list to c.
It's not really relevant whether the object that ab points to is mutable. val means that you cannot in the future assign ab to another value, while var allows it.
Try repeating the assignment in each case and see what happens:
scala> val ab = List(1,2,3)
ab: List[Int] = List(1, 2, 3)
scala> ab = List(1,2,3)
reassignment to val; not found: value ab
scala> var ab = List(1,2,3)
ab: List[Int] = List(1, 2, 3)
scala> ab = List(1,2,3)
ab: List[Int] = List(1, 2, 3)
It's a question of style.
In Scala using a val is generally preferred to using a var as in (functional) programming immutability makes it easier to reason about a program.
So if you can get what you want without resorting to var it is the way to go.
A typical application of a var would be if you want to use an immutable data structure and update it benifitting of structural sharing.
var data = List.empty[String] // var is importan here
def addToData(s: String) : Unit = { data = s :: data }
The same could be achieved by using a mutable datastructure
import scala.collection.mutable.ArrayBuffer
val data = ArrayBuffer.empty[String]
data += "Hello" // this function is here from the beginning
For an in depth discussion look at https://stackoverflow.com/a/4440614/344116 .

Scala collection one-to-one mapping?

Pardon me if it's simple, but what is the most efficient way to do the following in scala:
Say I have two collections A and B with exactly same number of elements. For example,
A = {objectA1, objectA2, .... objectAN}
B = {objectB1, objectB2, .... objectBN}
I would like to get {{objectA1, objectB1}, {objectA2, objectB2}, ... {objectAN, objectBN}}. Note that these collections might be very large.
Some additions to #Tomasz answer: If collections are very large it is inefficient to use a zip b because it will create a complete intermediate collection. There is an alternative:
scala> (a,b).zipped
res15: scala.runtime.Tuple2Zipped[Int,Seq[Int],Char,Seq[Char]] = scala.runtime.Tuple2Zipped#71060c3e
scala> (a,b,b).zipped // works also for Tuple3
res16: scala.runtime.Tuple3Zipped[Int,Seq[Int],Char,Seq[Char],Char,Seq[Char]] = scala.runtime.Tuple3Zipped#30b688e1
Internally, Tuple2Zipped and Tuple3Zipped use iterators. This makes it more efficient when you want to transform the zippers.
Zip them:
A zip B
Example:
scala> val a = Seq(1, 2, 3, 4, 5)
a: Seq[Int] = List(1, 2, 3, 4, 5)
scala> val b = Seq('a', 'b', 'c', 'd', 'e')
b: Seq[Char] = List(a, b, c, d, e)
scala> a zip b
res5: Seq[(Int, Char)] = List((1,a), (2,b), (3,c), (4,d), (5,e))
If A and B are iterators, this will create an iterator of pairs as well.

What is the difference between val b=a (a is an Array) and val b=a.clone()?

I am reading scaladocs and just wondering difference between direct assignment and .clone method.
val a=Array(1,2,3,4,5)
case 1:
val b=a
case 2 :
val b=a.clone()
Consider this:
scala> val a=Array(1,2,3,4,5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
scala> val b = a
b: Array[Int] = Array(1, 2, 3, 4, 5)
scala> val c = a.clone()
c: Array[Int] = Array(1, 2, 3, 4, 5)
scala> b(0) = 0
scala> c(1) = 1
scala> a
res2: Array[Int] = Array(0, 2, 3, 4, 5)
scala> b
res3: Array[Int] = Array(0, 2, 3, 4, 5)
scala> c
res4: Array[Int] = Array(1, 1, 3, 4, 5)
As you can see, when you do val b = a, then a and b point to the same object. When the object is changed, the change will be seen by both.
On the other hand, when you clone the array, you produce a new array with the same content. Changing this new array does not change the old one.
I believe case 1 just sets the reference of a to b while case 2 creates an entirely new array that is a copy of a and putting the value in b.
In other words if you in case a edit the a array the b array will also be edited this is not the case in case 2
Here is an answer in code:
scala> val a = Array(1,2,3,4,5)
scala> a.hashCode()
res12: Int = 1382155266
scala> val b = a
scala> b.hashCode()
res13: Int = 1382155266
scala> val c = a.clone()
scala> c.hashCode()
res14: Int = 2062756135
scala> a eq b
res15: Boolean = true
scala> a eq c
res16: Boolean = false
scala> b eq c
res17: Boolean = false
In case 1, both reference leads to the same object while in the second case, a new object is created and a and b do not reference the same object.