Scala how to pattern match for a None array - arrays

For the following method, what is the way to check if the incoming array is None (aka null fro java land..)
val x = Array(22.0,122,222,322,422,522,622,722,822,922)
def stddev(arr :Array[Double]) = {
arr match {
case None => 0
..
The error is:
<console>:11: error: pattern type is incompatible with expected type;
found : None.type
required: Array[Double]
Note: if you intended to match against the class, try `case _: <none>`
case None => 0
^

null isn't equals to None. You should wrap your array in Option:
Option(arr) match {
case Some(a) => ...
case None => ...
}
Option(null) returns None
More complete sample:
def printDoubles(arr: Array[Double]) {
Option(arr) match {
case Some(Array()) => println("empty array")
case Some(a) => println(a mkString ", ")
case None => println("array is null")
}
}
printDoubles(null) // array is null
printDoubles(Array.empty) // empty array
printDoubles(Array(1.0, 1.1, 1.2)) // 1.0, 1.1, 1.2

Related

MEL Expression for filtering the value of a Variable

I have stored a value in a Variable. Its an ID, it looks like this 1-2823596-1 or CAT-R131-L6267. Now I need to write an expression which filters this ID based on the first value of the ID(i.e if it's number or alphabet). According to that I will put my choice router. Can anyone please let me know how to write this expression as I am relatively new to Mulesoft
tried with the given example but did't able to create
enter code here { a: payload.a match {
case is Object -> 'OBJECT'
case is String -> 'STRING'
case is Number -> 'NUMBER'
case is Boolean -> 'BOOLEAN'
case is Array -> 'ARRAY'
case is Null -> 'NULL'
else -> 'ANOTHER TYPE' }, b: payload.b match {
case y is Object -> { 'Type': { 'OBJECT' : y} }
case y is String -> { 'Type': { 'STRING' : y} }
case y is Number -> { 'Type': { 'NUMBER' : y} }
case y is Boolean -> { 'Type': { 'BOOLEAN' : y} }
case y is Array -> { 'Type': { 'ARRAY' : y} }
case y is Null -> { 'Type': { 'NULL' : y} }
else -> { 'Type': { 'ANOTHER TYPE' : payload.b} } }}
Also tried using substring
enter code here #[vars.reqTcpn == vars.reqTcpn[0..0] match[0-9]]
Required to check if the first value of the string is a character or number so that I can put a choice router
You are using Mule 4, so MEL has been replaced with Dataweave as the expression language.
In Mule 4.2 and Dataweave 2.2.0, both recently released, there is a new isNumeric function that does just this:
import isNumeric from dw::core::Strings output application/java --- isNumeric(vars.reqTcpn[0 to 0])
https://docs.mulesoft.com/mule-runtime/4.2/dw-strings-functions-isnumeric
MulE 4 versions < 4.2 you can use a combination of substring[0 to 0] and match for regex to check it's numeric. Then sizeOf to check that there is at least 1 match:
#[sizeOf(match(vars.reqTcpn[0 to 0], '[0-9]')) > 0]

Pattern match an array of Regex's in Scala

I have an array of regex's in Scala, and am trying to verify that a message body contains anything in the regex. However, in the messageBody variable I'm getting a Pattern type is incompatible with given type, expected Array[Regex], found Array[String]. How can I pass in a proper case?
A few other posts have suggested using Pattern but that hasn't worked in my case.
val messageBody: Array[String] = message.body.split(' ')
val unsubscribeTriggers: Array[Regex] = Array("unsubscribe/i".r, "stop/i".r, "stopall/i".r, "cancel/i".r, "end/i".r, "quit/i".r)\
if (messageBody.length == 1) {
unsubscribeTriggers match {
case `messageBody` => true
case _ => false
}
}
You expect too much magic from the compiler. If you have a collection of regexes, you have to check yourself against every element:
val unsubscribeTriggers: Array[Regex] = Array("(?i)unsubscribe".r, "(?i)stop".r)
val body = "sToP"
val matchFound = unsubscribeTriggers.exists { p: Regex =>
body match {
case p() => true
case _ => false
}
}
println(matchFound)
Regex is made case insensitive by adding (?i) at the start. Try it.
This will tell you if any of the Regex patterns match the 1st element in the massageBody array.
unsubscribeTriggers.exists(_.findAllIn(messageBody.head).nonEmpty)
But I don't think your regex patterns do what you want. What is the /i extension? If you mean for it to ignore case, it won't. It's also not a very efficient or Scala-esque way to do it. Instead of many smaller regex patterns, combine them into a single test.
val unsubscribeTriggers: Array[String] =
Array("unsubscribe/i", "stop/i", "stopall/i", "cancel.i", "end/i", "quit/i")
val TriggersRE = unsubscribeTriggers.mkString("(", "|", ")").r
messageBody.head match {
case TriggersRE(_) => true
case _ => false
}
update
If you just need to compare strings, ignoring case, then try this.
val unsubscribeTriggers: Array[String] =
Array("unsubscribe", "stop", "stopall", "cancel", "end", "quit")
unsubscribeTriggers.exists(messageBody.head.equalsIgnoreCase)
If you want to test if any element in massageBody matches any element in unsubscribeTriggers then try this.
unsubscribeTriggers.exists(t => messageBody.exists(t.equalsIgnoreCase))
You can match on regex individual variables pretty cleanly also.
val messageBody: Array[String] = message.body.split(' ')
val unsubscribe = "(?i)unsubscribe".r
val stop = "(?i)stop".r
val stopall = "(?i)stopall".r
val cancel = "(?i)cancel".r
val end = "(?i)end".r
val quit = "(?i)quit".r
val shouldUnsubscribe = messageBody.headOption.exists {
case unsubscribe() => true
case stop() => true
case stopall() => true
case cancel() => true
case end() => true
case quit() => true
case _ => false
}

unable to return an Array from a class

Trying to understand 'apply' method. I want to create a class which returns either a List, Array or a Set depending on the argument passed. The code works for List and Set but not for Array. I am not able to understand the issue
class CollectionFactory [A](s:String){}
object CollectionFactory {
def apply[A](s: String): Traversable[A] = {
s match {
case "list" => {
List[A]()
}
//this doesnt work. It seems using [A] is incorrect. How do I specify the type?
/*
case "array" => {
new Array[A](1)
}
*/
case _ => {
Set[A]() }
}
}
}
val c = CollectionFactory[Int]("list")
c: Traversable[Int] = List()
CollectionFactory[String]("list")
res0: Traversable[String] = List()
CollectionFactory[Boolean]("")
res1: Traversable[Boolean] = Set()
You need a ClassTag[A] to instantiate a new Array[A]. This is easy to fix by adding an implicit ct: ClassTag[A] parameter.
object CollectionFactory {
def apply[A: reflect.ClassTag](s: String): Traversable[A] = {
s match {
case "list" => List[A]()
case "array" => new Array[A](1)
case _ => Set[A]()
}
}
}

Parsing text file lines into numbers using std::iter::Iterator map

I'm trying to read and parse a text file in Rust. Each line is a signed integer. I'm able to do it using for line in lines iteration but I'm unable to do it with a iter().map(|l| ...) one-liner. I'm getting a
expected `&core::result::Result<collections::string::String, std::io::error::Error>`,
found `core::result::Result<_, _>`
when I try to pattern match Ok(s) => match s.parse() but I'm unable to get to the bottom of what I am doing wrong. The whole example is below. The code on the bottom is the code that is producing the error.
Can anyone tell what I am doing wrong?
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;
fn main() {
// Create a path to the desired file
let path = Path::new("input/numbers.txt");
let display = path.display();
// Open the path in read-only mode, returns `io::Result<File>`
let file = match File::open(&path) {
// The `description` method of `io::Error` returns a string that describes the error
Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
Ok(file) => file,
};
// Collect all lines into a vector
let reader = BufReader::new(file);
let lines: Vec<_> = reader.lines().collect();
// Works.
let mut nums = vec![];
for l in lines {
println!("{:?}", l);
let num = match l {
Ok(s) => match s.parse() {
Ok(i) => i,
Err(_) => 0
},
Err(_) => 0
};
nums.push(num);
}
// Doesn't work!
let nums: Vec<i64> = lines.iter().map(|l| match l {
Ok(s) => match s.parse() {
Ok(i) => i,
Err(_) => 0
},
Err(_) => 0
});
}
Let's look at the complete error message, which points to the error for us:
<anon>:5:9: 5:14 error: mismatched types:
expected `&core::result::Result<&str, ()>`,
found `core::result::Result<_, _>`
(expected &-ptr,
found enum `core::result::Result`) [E0308]
<anon>:5 Ok(s) => match s.parse() {
^~~~~
The compiler is expecting a &Result, but found a Result, and the issue is with the Ok(s) pattern. The type of l is a reference to a Result because you are using iter - which returns an iterator of references to the items in the vector.
The shortest fix is to add a & to the pattern match for the closure variable:
fn main() {
let lines: Vec<Result<_, ()>> = vec![Ok("1"), Ok("3"), Ok("5")];
// HERE V
let nums: Vec<i64> = lines.iter().map(|&l| match l {
Ok(s) => match s.parse() {
Ok(i) => i,
Err(_) => 0
},
Err(_) => 0
}).collect();
println!("{:?}", nums)
}
I also had to add collect to go back to a Vec.
The other change you could make would be to consume the input vector using into_iter and then iterate on each value in the vector:
// HERE V~~~~
let nums: Vec<i64> = lines.into_iter().map(|l| match l {
And for good measure, you could use ok, and_then, and unwrap_or to say the same thing a bit more succinctly:
let nums: Vec<i64> = lines.into_iter().map(|l| {
l.ok().and_then(|s| s.parse().ok()).unwrap_or(0)
}).collect();

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.

Resources