Adding 2 characters in scala - arrays

I am new to Scala and I was working on something,
I need to implement the following code
class $(val text2d: Array[Array[Char]]) {
def +(that: $) = ...
}
But my code keeps giving me an error stating
found : Array[Array[Char]]
required: String
Here is what my code looks like:
class Point2D(val text2D : Array[Array[Char]]) {
def +(that : Point2D): Point2D =
new Point2D(text2D + that.text2D)
override def toString = {
s"${text2D}"
}
}
Any help would be appreciated.

You have to use the ++ method to join two arrays into a new one.
class Point2D(val text2D: Array[Array[Char]]) {
def +(that: Point2D): Point2D =
new Point2D(text2D ++ that.text2D)
}

Related

Flink RichSinkFunction implementation as anonymous class cant access class members. Throws not serializable exception

I am stuck at this issue for quite a while. I know the solution but I dont know the correct reason behind this
Case a - Doesnt Work
class DBSinkForPrimaryKeyedTables(a: A, b: B, c: DataStream[Row]) extends Serializable {
val primaryKey: String = a.primaryKey
val tableName: String = a.tableName
def sink: {
c.addSink(new RichSinkFunction[Row] {
override def open(parameters: Configuration): Unit = {
super.open(parameters)
println(primaryKey)
}
override def invoke(value: Row, context: Context): Unit = {
//Some code
}
})
}
Case B - Works
class DBSinkForPrimaryKeyedTables(a: A, b: B, c: DataStream[Row]) extends Serializable {
val primaryKey: String = a.primaryKey
val tableName: String = a.tableName
def sink: {
c.addSink(new DBRichSinkFunction(primaryKey))
}
}
class DBRichSinkFunction(primaryKey: String) extends RichSinkFunction[Row] {
override def open(parameters: Configuration): Unit = {
super.open(parameters)
println(primaryKey)
}
override def invoke(value: Row, context: Context): Unit = {
//Some code
}
}
Note - A and B are case classes. And I know for sure that when I am trying to access the val primaryKey then only I am facing this the issue.
The implementation which doesnt work throws
Exception in thread "main" org.apache.flink.api.common.InvalidProgramException: The implementation of the DataStream is not serializable. The object probably contains or references non serializable fields.
Caused by: java.io.NotSerializableException: org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator
I was under the impression that anonymous classes can access the members of the class in which they are enclosed but thats not happening here.

Circe: Json object to Custom Object

I've go this json node
...
"businessKeys": [
"product://color?product_code",
"product://?code"
]
...
after a sequence of computation I have a Json istance but I'm not able to understand how I can transform that object into a List of my object. So Json (istance) to List[MyClass].
MyClass(root: ParameterType, children: List[ParameterType] = List.empty)
ParameterType(parameter: String)
I have a method that transform a String into a MyClass istance, so I need to decode Json into List[String] and then call my function or there is a direct method?
Thanks
You need implement our own io.circe.Decoder, in your case it can be converted from decoder for string.
Please, find some example code below:
import io.circe._
import io.circe.generic.auto._
object CirceExample {
class ParameterType(parameter: String) {
override def toString: String = parameter
}
class MyClass(root: ParameterType, children: List[ParameterType] = List.empty) {
override def toString: String = s"MyClass($root, $children)"
}
object MyClass {
/**
* Parsing logic from string goes here, for sake of example, it just returns empty result
*/
def parse(product: String): Either[String, MyClass] = {
Right(new MyClass(new ParameterType("example")))
}
// This is what need - just declare own decoder, so the rest of circe infrastructure can use it to parse json to your own class.
implicit val decoder: Decoder[MyClass] = Decoder[String].emap(parse)
}
case class BusinessKeys(businessKeys: List[MyClass])
def main(args: Array[String]): Unit = {
val json = "{ \"businessKeys\": [\n \"product://color?product_code\",\n \"product://?code\"\n ] }"
println(parser.parse(json).map(_.as[BusinessKeys]))
}
}
Which in my case produced next output:
Right(Right(BusinessKeys(List(MyClass(example, List()), MyClass(example, List())))))
Hope this will help you!

Data Class Either Object or Array

I have a Kotlin data class that has an arg that can either be an Object or Array. Is there a way to de-serialize a string into this class and not care if not an Array but somehow get it into an array of one?
data class Game(var name:List<NameItem>)
data class NameItem(var title: String, var id: Int)
data can come back as both ways a single object or an array of objects( I have no control over the data as it is 3rd party data.
jsonString = "{"game":{"name":{"title":"GameName","id":22}}}"
jsonString = "{"game":{"name":[{"title":"GameName","id":22},{"title":"GameName2","id":23}]}}"
game: Game? = Gson().fromJson(jsonString Game::class.java)
You have to write a custom JsonDeserializer. Both or your class should have the same parent class. Then, write a custom JsonDeserializer for this specific type.
For example:
sealed class GameParent() {
data class Game(val name: String): GameParent()
data class GameList(val games: List<Game>): GameParent()
}
class GameDeserializer : JsonDeserializer<GameParent> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): GameParent {
with(json) {
if(isJsonObject) {
// parse as Game
}
if(isJsonArray) {
// parse as GameList
}
}
}
}
Then, in your GsonBuilder you have to register this custom JsonDeserializer:
gsonBuilder.registerTypeAdapter(GameParent::class.java, GameDeserializer());
Now, whenever your Gson expect GameParent will use registered deserializer.
my suggestions for solving your task
my solution if name is object, replace it with arrays
data class Game(var name:List<NameItem> )
data class NameItem(var title: String, var id: Int)
fun main(args: Array<String>) {
var json = "{\"game\":{\"name\":[{\"title\":\"game 1\",\"id\":1},{\"title\":\"game 2\",\"id\":2}]}}"
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1), NameItem(title=game 2, id=2)])
json = "{\"game\":{\"name\":[{\"title\":\"game 1\",\"id\":1}]}}"
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1), NameItem(title=game 2, id=2)])
json = "{\"game\":{\"name\":{\"title\":\"game 1\",\"id\":1}}}" // not array
println(useJsonParser(json)) //Game(name=[NameItem(title=game 1, id=1)])
}
version 1 -- created and registry adapter link #Cililing
fun useJsonParser(json: String): Game? {
val gson = GsonBuilder().registerTypeAdapter(Game::class.java, GameDeserializer()).create()
return gson.fromJson(json, Game::class.java)
}
class GameDeserializer : JsonDeserializer<Game?> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): Game? {
val gameJson = json!!.asJsonObject.get("game")
if (gameJson.isJsonObject) {
val jsonName = gameJson.asJsonObject["name"]
val list = if (jsonName.isJsonObject) {
arrayOf(Gson().fromJson(jsonName, NameItem::class.java))
} else {
val fromJson = Gson().fromJson(jsonName, Array<NameItem>::class.java)
fromJson
}.toList()
return Game(list)
}
return null
}
}
version 2 -- manipulating the response
fun useJsonParser(json:String):Game?{
val jsonObject = JsonParser().parse(json).asJsonObject.get("game")
if(jsonObject.asJsonObject["name"].isJsonObject){
val jsonName = jsonObject.asJsonObject["name"].asJsonObject
val array = JsonArray()
array.add(jsonName)
jsonObject.asJsonObject.add("name", array) // rewrite origin JSON
}
return Gson().fromJson(jsonObject, Game::class.java)
}
vesrion 3 -- add adapter TypeToken>()
fun useJsonParser(json: String): Game? {
val type = object : TypeToken<MutableList<NameItem>>() {}.type
val gson = GsonBuilder().registerTypeAdapter(type, NameItemDeserializer()).create()
return gson.fromJson(JsonParser().parse(json).asJsonObject.get("game"), Game::class.java)
}
class NameItemDeserializer : JsonDeserializer<List<NameItem>?> {
override fun deserialize(json: JsonElement, type: Type, context: JsonDeserializationContext?): List<NameItem>? {
with(json){
return if(isJsonObject){
arrayListOf(Gson().fromJson(this,NameItem::class.java))
}else{
Gson().fromJson(this,Array<NameItem>::class.java).toList()
}
}
}
}

How to return a type parameter that is a subtype of an Array?

I don't understand why this code is impossible in Scala:
def getColumns[T <: Array[_]] ():Array[(String,T)] ={
Array(Tuple2("test",Array(1.0,2.0,3.0)))
}
Compiler says:
Expression of type Array[(String,Array[Double])] doesn't conform to expected type Array[(String, T)]
I have the same error with this code:
def getColumns[T <: Array[Double]] ():Array[(String,T)] ={
Array(Tuple2("test",Array(1.0,2.0,3.0)))
}
It's more clear with my complete use case, finally I have chosen an Array[AnyVal]:
class SystemError(message: String, nestedException: Throwable) extends Exception(message, nestedException) {
def this() = this("", null)
def this(message: String) = this(message, null)
def this(nestedException : Throwable) = this("", nestedException)
}
class FileDataSource(path:String) {
val fileCatch = catching(classOf[FileNotFoundException], classOf[IOException]).withApply(e => throw new SystemError(e))
def getStream():Option[BufferedSource]={
fileCatch.opt{Source.fromInputStream(getClass.getResourceAsStream(path))}
}
}
class CSVReader(src:FileDataSource) {
def lines= src.getStream().get
val head = lines.getLines.take(1).toList(0).split(",")
val otherLines = lines.getLines.drop(1).toList
def getColumns():Array[(String,Array[_])] ={
val transposeLines = otherLines.map { l => l.split(",").map {
d => d match {
case String => d
case Int => d.toInt
case Double => d.toDouble
}}.transpose }
head zip transposeLines.map {_.toArray}
}
}
Can you give me some explanation or good links to understand the issues?
Because your function must be able to work with any T (any array type), however, it will always return an Array[(String,Array[Double])].
A simpler working signature would be:
def getColumns[T](): Array[(String,Array[T])]
But in the body of the function you will have to create an array of type T.
Your function signature requires a T in the compound return type, but you give it a Array[Double]. Note that T <: Array[Double], not the other way around. The following code works:
def getColumns[T >: Array[Double]] ():Array[(String,T)] ={
Array(Tuple2("test",Array(1.0,2.0,3.0)))
}
Shouldn't be what you want but just for elaborating the problem.

Groovy ConfigSlurper Configure Arrays

I am trying to create a config that would look something like this:
nods = [
nod {
test = 1
},
nod {
test = 2
}
]
and then use configSlurper to read it but the "node" objects appear to be null after the read.
Here is my code:
final ConfigObject data = new ConfigSlurper().parse(new File("config.dat").toURI().toURL())
println data.nods
and the output:
[null, null]
What am I doing wrong?
Thanks!
It think I resolved it this way:
config {
nods = [
['name':'nod1', 'test':true],
['name':'nod2', 'test':flase]
]
}
And then using it like:
config = new ConfigSlurper().parse(new File("config.groovy").text)
for( i in 0..config.config.nods.size()-1)
println config.config.nods[i].test
Hope this helps someone else!!
You have to be careful when using ConfigSlurper when doing this sort of thing.
For example your solution will actually produce the following output:
true
[:]
If you look carefully you will notice that there is a typo on the second array value flase instead of false
The following:
def configObj = new ConfigSlurper().parse("config { nods=[[test:true],[test:false]] }")
configObj.config.nods.each { println it.test }
should produce the correct result:
true
false
I tried to parse with ConfigSlurper something like this:
config {sha=[{from = 123;to = 234},{from = 234;to = 567}]}
The array "sha" was far from what expected.
To get "sha" as an array of ConfigObjects I used a helper:
class ClosureScript extends Script {
Closure closure
def run() {
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure.delegate = this
closure.call()
}
}
def item(closure) {
def eng = new ConfigSlurper()
def script = new ClosureScript(closure: closure)
eng.parse(script)
}
this way I get an array of ConfigObjects:
void testSha() {
def config = {sha=[item {from = 123;to = 234}, item {from = 234;to = 567}]}
def xx = item(config)
assertEquals(123, xx.sha[0].from)
}

Resources