Pattern match an array of Regex's in Scala - arrays

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
}

Related

Using _.some in lodash

I have Typescript code where i want to return true if any items in 1 array are present in another array. I am new to lodash but i was looking to do this using _.some. I am not sure if this is the correct approach. The code below is returning false but i expected it to return true.
let array1 = ["test", "some", "lodash"];
let array2 = ["some", "includes"];
let condition : boolean = _.some(array1, array2);
You can use intersection function and check if it returns any items:
let condition : boolean = _.intersection(array1, array2).length > 0;
With some you have to pass a test callback as a second argument:
let condition : boolean = _.some(array1, item => array2.includes(item))
lodash was cool before plain javascript had the same methods...
let array1 = ["test", "some", "lodash"];
let array2 = ["some", "includes"];
let test = array1.some(e => array2.includes(e));
console.log(test);

Finding if one Array [(String,Bool)] contains any strings from Array2[String] in swift 4

var fakeArray [("Potato", True),("root", false),("dog", False),("cat", True)]
var OtherFakeArray ["person","cat","dog","figg"]
var finalArrat[(String,Bool)]
I want to find any item in first array that is in second array, append it to the final, both string and bool, and then copy the rest of the items that were not found in FakeArray and also append them to finalArray while applying FALSE bool to each so they can be stored in final array, so the result should be
finalArray[("dog",false),("cat",True),("figg", False),("person",False)]
So the final array includes all entries from otherFakeArray , the ones that could be matched with fakeArray have their original bool states, while the ones that were not found get a new False state to be added to the final one.
Filter out all the contents from the fakerArray that are contained in otherFakerArray. Find out all the items that are not contained and make (_, false) tuple from it and append to the ones that are contained.
Something like this,
var result = fakeArray.filter { OtherFakeArray.contains($0.0) }
let notFoundItems = OtherFakeArray.filter { item in
!result.contains(where: { $0.0 == item })
}.map { ($0, false) }
result += notFoundItems
print(result)
And here is bit better version,
let result = OtherFakeArray.map { string in
fakeArray.first(where: { $0.0 == string}) ?? (string, false)
}
Your code review
You are not using the Swift boolean type. It should be one of true or false and cannot be True and False. Didnt you try to compile it with xcode. It should not have compiled. How did you come up with the question without actually trying anything.
Here is how your actual type should look.
let fakeArray = [("Potato", true),("root", false),("dog", false),("cat", true)]
let OtherFakeArray = ["person","cat","dog","figg"]
You can try
let res1 = fakeArray.filter { otherFakeArray.contains($0.0) }
let tem = fakeArray.map { $0.0 }
let final = otherFakeArray.filter { !tem.contains($0)}.map { ($0,false)} + res1

What is the Best way to loop over an array in scala

I'm new to scala and I'm trying to refactor the below code.I want to eliminate "index" used in the below code and loop over the array to fetch data.
subgroupMetricIndividual.instances.foreach { instanceIndividual =>
val MetricContextListBuffer: ListBuffer[Context] = ListBuffer()
var index = 0
contextListBufferForSubGroup.foreach { contextIndividual =>
MetricContextListBuffer += Context(
entity = contextIndividual,
value = instanceIndividual(index).toString
)
index += 1
}
}
For instance, if the values of variables are as below:
contextListBufferForSubGroup = ("context1","context2")
subgroupMetricIndividual.instances = {{"Inst1","Inst2",1},{"Inst3","Inst4",2}}
Then Context should be something like:
{
entity: "context1",
value: "Inst1"
},
{
entity: "context2",
value: "Inst2"
},
{
entity: "context1",
value: "Inst3"
},
{
entity: "context2",
value: "Inst4"
}
Note:
instanceIndividual can have more elements than those in contextListBufferForSubGroup. We must ignore the last extra elements in instanceIndividual in this case
You can zip two lists into a list of tuples and then map over that.
e.g.
subgroupMetricIndividual.instances.foreach { instanceIndividual =>
val MetricContextListBuffer = contextListBufferForSubGroup.zip(instanceIndividual).map {
case (contextIndividual, instanceIndividualIndex) => Context(
entity = contextIndividual,
value = instanceIndividualIndex.toString
)
}
}
If Context can be called like a function i.e. Context(contextIndividual, instanceIndividualIndex.toString) then you can write this even shorter.
subgroupMetricIndividual.instances.foreach { instanceIndividual =>
val MetricContextListBuffer = contextListBufferForSubGroup
.zip(instanceIndividual.map(_.toString)).map(Context.tupled)
}
Without knowing your exact datatypes, I'm mocked up something which is probably close to what you want, and is slightly more functional using maps, and immutable collections
case class Context(entity:String, value:String)
val contextListBufferForSubGroup = List("context1","context2")
val subgroupMetricIndividualInstances = List(List("Inst1","Inst2",1),List("Inst3","Inst4",2))
val result: List[Context] = subgroupMetricIndividualInstances.map { instanceIndividual =>
contextListBufferForSubGroup.zip(instanceIndividual) map { case v: (String, String) =>
Context(
entity = v._1,
value = v._2
)
}
}.flatten

Mapping swift enum with associated values

Let say we have an enum with associated value types. In the example below the two value types are simple object that hold an image and a url to share.
enum Content {
case Image(ShareableImage)
case Video(ShareableVideo)
}
Now let's have an array of video and image cases.
let media: [Content] = [*a lot of enum cases inside here*]
All the code above so far cannot be changed in any way in the codebase, I need to work with it.
Here starts my problem:
Let's filter the array with media to only image cases
let imageOnlyCases: [Content] = media.filter { item -> Bool in
switch item {
case .Image: return true
default: return false
}
}
Next step, I want to get from array of enum to an array of their associated values
[Content] -> [ShareableImage] by using map.
so I do this
let shareablemages = imageOnlyCases.map { imageCase -> ShareableImage in
switch imageCase {
case .Image(let image): return image
default: return WHAT TO DO HERE?
}
}
You see, I have a problem with return type..I know that the enum cases are all .Image..and I want a simple map. But the swift syntax is not helping me.
Any ideas?
You could return image for case .Image, and nil otherwise, within a .flatMap operation (to "filter" out nil entries):
/* Example */
enum Foo {
case Bar(Int)
case Baz(Int)
}
let foo: [Foo] = [.Bar(1), .Bar(9),. Baz(3), .Bar(39), .Baz(5)]
/* 1. using 'switch' */
let barOnlyValues: [Int] = foo.flatMap {
switch $0 {
case .Bar(let val): return val
case _: return nil
}}
/* 2. alternatively, as pointed out in MartinR:s answer;
as you're only looking for a single case, the alternative
'if case let' clause could be preferred over 'switch': */
let barOnlyValuesAlt: [Int] = foo.flatMap {
if case let .Bar(val) = $0 { return val }
else { return nil }}
print(barOnlyValues) // [1, 9, 39]
Applied to your use case: note that you needn't perform the filtering to create the imageOnlyCases array, as you can apply the above directly on the media array:
/* 1. using switch */
let shareableImages : [ShareableImage] = media.flatMap {
switch $0 {
case .Image(let image): return image
case _: return nil
}}
/* 2. 'if case let' alternative, as per MartinR:s suggestion */
let shareableImagesAlt : [ShareableImage] = media.flatMap {
if case let .Image(image) = $0 { return image }
else { return nil }}
Disclaimer: I cannot verify your specific use case in practice as I don't have access to the ShareableImage class/struct.
(Thanks #MartinR for advice that .map{ ... }.flatMap{ ... } can be simplified to just .flatMap{ ... }).
If it is guaranteed that only the .Image case can occur then
you can call fatalError() in all other cases:
let shareableImages = imageOnlyCases.map { imageCase -> ShareableImage in
if case let .Image(image) = imageCase {
return image
} else {
fatalError("Unexpected content")
}
}
fatalError() causes the program to terminate immediately. It is
only meant for situations that "cannot occur", i.e. to find programming
errors.
It satisfies the compiler because the function is marked as #noreturn.
If you cannot make that guarantee then use flatMap() as suggested
in the other answer.
Note also that you can use if case here with a pattern instead
of switch/case.

Scala how to pattern match for a None array

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

Resources