Join array of strings? - reason

In JavaScript you can join an array of strings, e.g.:
fruits = ["orange", "apple", "banana"];
joined = fruits.join(", ");
console.log(joined)
// "orange, apple, banana"
How do you do this in ReasonML?

You can use Js.Array.joinWith:
let fruits = [|"orange", "apple", "banana"|];
let joined = Js.Array.joinWith(", ", fruits);
Js.log(joined);
// "orange, apple, banana"

Converting an array to a string of joined values sounds like a job for Array.fold_left, however running
Array.fold_left((a, b) => a ++ "," ++ b, "", fruits);
produces ",orange,apple,banana".
Ideally the starting value for the fold (second argument) should the the first element in the array and the array actually used would be the rest, this avoids the initial comma. Unfortunately, this isn't easily doable with arrays, but is with lists:
let fruitList = Array.to_list(fruits);
let joined = List.fold_left((a, b) => a ++ "," ++ b, List.hd(fruitList), List.tl(fruitList));
/*joined = "orange,apple,banana"*/
Reasonml docs on lists

Here's how to implement your own join function in ReasonML:
let rec join = (char: string, list: list(string)): string => {
switch(list) {
| [] => raise(Failure("Passed an empty list"))
| [tail] => tail
| [head, ...tail] => head ++ char ++ join(char, tail)
};
};
With this, Js.log(join("$", ["a", "b", "c"])) gives you "a$b$c", much like JavaScript would.

Related

Fold left to create a immutable list

I am trying to create a list of string and then concatenate them using mkstring
List("a", "b1")
.foldLeft(ListBuffer.empty[String]) { (a, l) =>
{
if (StringUtils.isNotBlank(l))
a += "abc" +l
else a
}
}
.mkString(";")
Output
abca;abcb1
I want to used a mutable list .
Solution tried
List("a", "b1").
foldLeft(List[String]())((b,a) => b:+"abc"+a).mkString(";")
I can perform the empty check.Can we refactor it to better to get rid of if and else
List("a", "b1","","c2").
foldLeft(List[String]())((b,a) =>
if (StringUtils.isNotBlank(a))
b:+"abc"+a
else b
).mkString(";")
Can anyone help
List("a", "b1").foldLeft("") { case (acc, el) => acc + el }
You're slightly misusing foldLeft. The key thing to remember is that you pass in a function that takes an accumulator and the "current element", as well as a seed value, and feeds in the result of the "current" step as the "seed" or accumulator for the next step.
Reading from the top:
Take my list of List("a", "b1")
Starting from the empty string "" as the accumulator
For every element in the list, call the function against the "current" value of the accumulator.
In the above case, concatenate the "current" element to the existing accumulator.
Pass the result to the next step as the seed value.
There's no += like in your example, as you're not mutating the value, instead the return of the "current step", will be the initial accumulator value for the next step, it's all immutable.
In effect:
- Step 0: acc = "", el = "a", so you get "" + "a" = "a"(this is the value of acc at the next stage)
- Step 1: acc = "a", el = "b1", so you get "a" + "b1" = "ab1"
It's also worth nothing that the empty string "" is a the zero element for string concatenation, so there's no value in checking for empty.
For your specific example:
List("a", "b1").foldLeft("") { case (acc, el) =>
if (el.isEmpty) acc else acc + "abc" + el
}
In your case, collect is probably better
l.collect {
case s if s.nonEmpty => "abc" + s
} mkString ";"

List concatenation not working in scala

I am trying to concatenate scala list in loop using below code.
var names: List[String] = Nil
val cluster_id = List("149095311_0", "149095311_1")
for (id <- cluster_id) {
val influencers_name = searchIndex(s"id : $id", "id", "influencers", searcher)
println("In Loop " + influencers_name)
names :::= influencers_name
}
for(n <- names) println("List element -> " + n)
But when I iterate over final list it give me individual list's instead of individual elements of concatenated List.
Below is the O/P of above code:
In Loop List(kroger 10TV DispatchAlerts)
In Loop List(kroger seanhannity SenTedCruz)
List element -> kroger seanhannity SenTedCruz
List element -> kroger 10TV DispatchAlerts
Your code isn't very functional in that you are mutating variables. The following is more elegant:
def searchIndex(s: String): List[String] = {
if (s == "149095311_0") List("kroger 10TV DispatchAlerts")
else List("kroger seanhannity SenTedCruz")
}
val cluster_id = List("149095311_0", "149095311_1")
val names = cluster_id.foldLeft(List[String]()) {
(acc, id) => acc ++ searchIndex(id)
}
for(n <- names) println("List element -> " + n)
Where '++' is used to concatenate the elements of two lists.
The reason is,
When you do names ::: List("anything") -> it does not add anything to names.
Instead, it creates a new collection.
For example,
scala> var names: List[String] = Nil
names: List[String] = List()
scala> names ::: List("mahesh")
res0: List[String] = List(mahesh)
You can achive that
scala> names ::: List("chand")
res1: List[String] = List(chand)
scala> res0 ::: List("chand")
res2: List[String] = List(mahesh, chand)
When I added "Mahesh" to it, it has created new collection naming res0.
When I added again different string, here "chand" it has created another collection. But when I added "chand" to the created collection, it has concatenated to correct collection,
You can achive What you want to do,
scala> for(i <- List("a" ,"b" )){
| names = i :: names }
scala> names
res11: List[String] = List(b, a)
It looks like the problem is in searchIndex method that is retreiving a List[String] with a single String that contain all the values separated by a space, fix that method to make sure that it retrieves a List with one elemente per value.
To check if this is right try this, this is just a workaround, you should fix searchIndex
var names: List[String] = Nil
val cluster_id = List("149095311_0", "149095311_1")
for (id <- cluster_id) {
val influencers_name = searchIndex(s"id : $id", "id", "influencers", searcher).flatMap(_.split(' '))
("In Loop " + influencers_name)
names = influencers_name ::: names
}
for(n <- names) println("List element -> " + n)

Replace all elements of a Seq from a String

I have a String and a Seq like :
Array[String] = Array(a, the, an)
String = "This is a sentence that includes articles a, an and the"
I want to replace each element of the Seq within the String with ""
Currently, I'm doing something like :
val a = Array("a" , "the", "an" )
var str = "This is a sentence that includes articles a, an and the"
a.foldLeft( "" ){ (x,y) => str=str.replaceAll(s"\\b${x}\\b", ""); str }
It seems to be working but doesn't look very Scala-ish mostly because of the re-assignment of the string for each iteration.
Is there any other way to do this?
This seems to be the correct variant:
a.foldLeft(str){ case (acc,item) => acc.replaceAll(s"\\b${item}\\b", "")}
It's just
a.foldLeft(str) { (x,y) => x.replaceAll(s"\\b${y}\\b", "") }
For foldLeft, x is already the intermediate result you want, no need to store it in a var.
(As a side note, your original code doesn't work correctly in general: if a is empty, it'll return "" instead of str.)

Scala - Automatic Iterator inside pattern match

I have Array Data like this : [("Bob",5),("Andy",10),("Jim",7),...(x,y)].
How to do pattern matching in Scala? so they will match automatically based on Array Data that i have provided (instead of define "Case" one by one)
i mean dont like this, pseudocode :
val x = y.match {
case "Bob" => get and print Bob's Score
case "Andy" => get and print Andy's Score
..
}
but
val x = y.match {
case automatically defined by given Array => print each'score
}
Any Idea ? thanks in advance
If printing and storing results in an array is your main concern than the following will work well:
val ls = Array(("Bob",5),("Andy",10),("Jim",7))
ls.map({case (x,y) => println(y); y}) // print and store the score in an array
A bit confused about the question however if you just wish to print all the data in the array i would go about it doing this:
val list = Array(("Foo",3),("Tom",3))
list.foreach{
case (name,score) =>
println(s"$name scored $score")
}
//output:
//Foo scored 3
//Tom scored 3
Consider
val xs = Array( ("Bob",5),("Andy",10),("Jim",7) )
for ( (name,n) <- xs ) println(s"$name scores $n")
and also
xs.foreach { t => println(s"{t._1} scores ${t._2}") }
xs.foreach { t => println(t._1 + " scores " + t._2) }
xs.foreach(println)
A simple way to print the contents of xs,
println( xs.mkString(",") )
where mkString creates a string out of xs and separates each item by a comma.
Miscellany notes
To illustrate pattern matching on Scala Array, consider
val x = xs match {
case Array( t # ("Bob", _), _*) => println("xs starts with " + t._1)
case Array() => println("xs is empty")
case _ => println("xs does not start with Bob")
}
In the first case we extract the first tuple, and neglect the rest. In the first tuple we match against string "Bob" and neglect the second item. Moreover, we bind the first tuple to tag t, which is used in the printing where we refer to its first item.
The second case means every other case not covered.

scala build up string from iterating over map

if i have a map and want to build up a string from iterating over it, is there a way to have the final string be a result of an expression instead of defining a variable and modifying that inside a loop?
instead of this
val myMap = Map("1" -> "2", "3"->"4")
var s = ""
myMap foreach s += ...
i'd rather it be
var s = myMap something ...
I'd just map and mkString. For example:
val s = (
Map("1" -> "2", "3"->"4")
map { case (key, value) => "Key: %s\nValue: %s" format (key, value) }
mkString ("", "\n", "\n")
)
As for Daniel's answer, but with a couple of optimisations and my own formatting preferences:
val myMap = Map("1" -> "2", "3"->"4")
val s = myMap.view map {
case (key, value) => "Key: " + key + "\nValue: " + value
} mkString ("", "\n", "\n")
The optimisations:
By first creating a view of the map, I avoid creating an intermediate collection
On profiling, direct String concatenation is faster than String.format
You can do this with a fold:
scala> myMap.foldLeft("") { (s: String, pair: (String, String)) =>
| s + pair._1 + pair._2
| }
res0: java.lang.String = 1234
I'm fairly new to Scala, but you can try reduceLeft. It goes accumulating a partial value (the string being joined with every element). For example, if you want the keys (or the values) joined in a string, just do:
val s = myMap.keys.reduceLeft( (e, s) => e + s)
This results in "13"
This works also fine if you don't bother about your own formatting:
scala> Map("1" -> "2", "3"->"4").mkString(", ")
res6: String = 1 -> 2, 3 -> 4