Check if element wise condition in Scala list - scala

I would like to get a list such as
val mask = List(true, false, false, false, false)
when evaluating elementwise if an element is equal to "DoubleType"
val column_type = List("DoubleType", "LongType", "LongType", "LongType", "StringType")
I got something similar when using
val mask = new ListBuffer[String]()
for (name <- column_type)
mask += (name == "DoubleType").toString
But you can see that I had to turn every element into a string, otherwise I get an error. And this way I can't use it later as a mask.
What should I do? Any more scalastic way of solving this issue?

You can use .map with a predicate
val mask = column_type.map(_ == "DoubleType")

val mask=column_type.map(a=>a.equals("DoubleType"))

The most concise way to accomplish your goal is via map:
scala> val mask = column_type.map(_ == "DoubleType")
mask: List[Boolean] = List(true, false, false, false, false)
Scala has a rich suite of tools for operating on collections, see https://docs.scala-lang.org/overviews/scala-book/collections-methods.html for more details.

Related

How can i remap a list based on different conditions in scala?

I have a list of custom objects (Buffer [CustomObject] ) on which I'm applying .map, in order to return a list of (String,Boolean,Boolean,Boolean) only if at least one of the conditions on the element are met. The string is taken inside the custom object. The code is something like this :
list.map{ item=>
val string = item.string
val boolean1 = true
val boolean2 = true
val boolean3 = true
//-- some code to check the conditions -- //
if (!boolean1 || !boolean2 || !boolean3)
(string,boolean1,boolean2,boolean3)
else
null
}
The issue with this is that the list obviously contains some null values, and I need to remove them later. I also tried to use .collect() but without success, given that the conditions are more than one and must be checked with some code. I know I could use maybe a couple of .filter and .map in order to achieve this but my goal is to do everything in one iteration. Can you help me?
Thanks
Edit: found a "partial" solution, basically you can return an option and using .flatten or a .flatMap that automatically removes None values.
list.flatMap{ item=>
val string = item.string
val boolean1 = true
val boolean2 = true
val boolean3 = true
//-- some code to check the conditions -- //
if (!boolean1 || !boolean2 || !boolean3)
Some (string,boolean1,boolean2,boolean3)
else
None
}
But it is a kind of "ugly" solution, is there a more "elegant" one?
You can take advantage that flatMap on List threats Options as collections of at most one element.
list.flatMap { item=>
val string = item.string
val boolean1 = true
val boolean2 = true
val boolean3 = true
Option.when((!boolean1 || !boolean2 || !boolean3)) {
(string,boolean1,boolean2,boolean3)
}
}

How To iterate List[Result] and return one Boolean/Result?

I have a Future[List[Result]]
I need to run a logic for example if all items in the list are Result.Ok then return Result.Ok (or true), else return Result.BadRequest (or false)
I've tried:
futureResultList.map(temp => temp.forall(_ == true))
But this code works only when the list contains booleans. It does not work if it contains Result objects (When changing check to _ == Result.Ok)
To return a Boolean you just need to change the predicate in the forall call:
futureResultList.map(_.forall(_ == Result.Ok))
The simplest way to overview such an example is mapping. If you have a List of Result, but need a List of Boolean, then map it. Don't be afraid of mapping multiple times, it's way more readable in the long run :)
val futureResultList: Future[List[Result]] = ???
val futureBooleanList: Future[List[Boolean]] = futureResultList.map(_.map(_ == Result.OK))
val result = futureBooleanList.map(temp => temp.forall(_ == true))
or slightly more concise:
val futureResultList: Future[List[Result]] = ???
val result = futureResultList.map(_.map(_ == Result.OK)
.forall(_ == true))
and of course as the other people suggest, go directly to checking the equality on the Result object. But mapping is often useful to navigate between types and getting a clearer and more readable code.

Scala apply filter based on a flag

To apply a filter only when a flag is set to true, My current solution looks like this:
val list = List(5,17,25,80)
val checkAge = false
val ageCheckedList = list.filter(i => i>18)
The idea is that if checkAge is set to true, filter should be applied, but if checkAge is false, do not perform the filtering.
What's a concise way of expressing this? The best I've come up with is this:
ageCheckedList = list.filterNot(i => checkAge && i <= 18)
which is very confusing to read to say the least.
I think what you have is perfectly fine. You can invert the logic and that makes it a little more readable perhaps.
list.filter(i => !checkAge || i <= 18)
This basically says either we aren't checking age or the age is in the range.
The following might express your intent more clearly:
val ageCheckedList = if (checkAge) list.filter(_ > 18) else list

Build a List of Arrays recursively in Scala

I am newbie to Scala and I am trying to build a list of arrays recursively in scala, here is the code I have, it is not throwing any error when I run it, but, its not printing anything when I try unCons.foreach(println)
val Tot = 5
val Num = 5
var unCons = ListBuffer[String]()
for(j <- 1 to Tot)
{
var OurArr = ListBuffer[String]()
for(i <- 1 to Num)
{
OurArr:+("true")
}
unCons:+(OurArr.toList)
}
The result I am expecting is something like this
[[true, true, true, true, true],
[true, true, true, true, true],
[true, true, true, true, true],
[true, true, true, true, true],
[true, true, true, true, true]]
Any idea, where I am going wrong?
The "Scala way" might be to use List.fill
scala> List.fill(5)(List.fill(5)(true))
res0: List[List[Boolean]] = List(List(true, true, true, true, true), List(true, true, true, true, true), List(true, true, true, true, true), List(true, true, true, true, true), List(true, true, true, true, true))
You've got a number of issues going on.
First you're not properly assigning to the ListBuffer.
OurArr :+= "true"
Next you're unCons is the wrong type for what you're trying to do.
var unCons = ListBuffer[List[String]]()
After these fixes you'll want to look into good Scala practice, like avoiding the use of var whenever possible (and it is almost always possible).
One other thing: there's no recursion in this code. If you're trying to build a list recursively (as the question title suggests) then you need a completely different approach.
Any idea, where I am going wrong?
There are three errors you are making:
unCons is of type ListBuffer[String]. OurArr is also of type ListBuffer[String]. You are trying to add the collection OurArr to unCons which will give you a type mismatch error. unCons only accepts elements of a type String while you are trying to add elements of type ListBuffer[String] to it. So, first make your unCons of type ListBuffer[ListBuffer[String]] so that it can accept elements of type OurArr
You are using the :+ method to append elements to your OurArr collection OurArr:+("true"), which returns a new collection instead of editing that collection in place.
From the scaladoc:
def +:(elem: A): ListBuffer[A]
A copy of the list buffer with an element prepended.
In your case, you should use OurArr += ("true") which edits your collection in place and does not return a new collection.
You would guess that operations on mutable collections would return the same collection after operations. But that is NOT the case. Many operations on mutable collections return a new copy of the collection and you will need to capture that new collection.
This line: unCons:+(OurArr.toList) is causing the same issue as #2 above. The :+ operator is returning a new collection and you are not capturing that collection in a variable. Instead, you could use unCons += OurArr to edit the collection in place.
Last but not the least, you should AVOID VARS as far as possible in Scala. You will be surprised that you rarely ever need to use a var in Scala. For example, in your case: you used two vars:
var unCons = ListBuffer[String]()
var OurArr = ListBuffer[String]()
Both of them can be val's with no change on your code's behavior. Remember, when you declare an object as a val it does NOT mean you can'S change/edit the content of the object. THE only difference is that you can't change the pointer to point to some different memory address. So, in both your cases you can safely use vals:
So your code becomes:
val Tot = 5
val Num = 5
val unCons = ListBuffer[ListBuffer[String]]()
for(j <- 1 to Tot)
{
val OurArr = ListBuffer[String]()
for(i <- 1 to Num)
{
OurArr += ("true")
}
unCons += OurArr
}

Filter a list by item index?

val data = List("foo", "bar", "bash")
val selection = List(0, 2)
val selectedData = data.filter(datum => selection.contains(datum.MYINDEX))
// INVALID CODE HERE ^
// selectedData: List("foo", "bash")
Say I want to filter a List given a list of selected indices. If, in the filter method, I could reference the index of a list item then I could solve this as above, but datum.MYINDEX isn't valid in the above case.
How could I do this instead?
How about using zipWithIndex to keep a reference to the item's index, filtering as such, then mapping the index away?
data.zipWithIndex
.filter{ case (datum, index) => selection.contains(index) }
.map(_._1)
It's neater to do it the other way about (although potentially slow with Lists as indexing is slow (O(n)). Vectors would be better. On the other hand, the contains of the other solution for every item in data isn't exactly fast)
val data = List("foo", "bar", "bash")
//> data : List[String] = List(foo, bar, bash)
val selection = List(0, 2)
//> selection : List[Int] = List(0, 2)
selection.map(index=>data(index))
//> res0: List[String] = List(foo, bash)
First solution that came to my mind was to create a list of pairs (element, index), filter every element by checking if selection contains that index, then map resulting list in order to keep only raw elementd (omit index). Code is self explanatory:
data.zipWithIndex.filter(pair => selection.contains(pair._2)).map(_._1)
or more readable:
val elemsWithIndices = data.zipWithIndex
val filteredPairs = elemsWithIndices.filter(pair => selection.contains(pair._2))
val selectedElements = filteredPairs.map(_._1)
This Works :
val data = List("foo", "bar", "bash")
val selection = List(0, 2)
val selectedData = data.filter(datum => selection.contains(data.indexOf(datum)))
println (selectedData)
output :
List(foo, bash)
Since you have a list of indices already, the most efficient way is to pick those indices directly:
val data = List("foo", "bar", "bash")
val selection = List(0, 2)
val selectedData = selection.map(index => data(index))
or even:
val selectedData = selection.map(data)
or if you need to preserve the order of the items in data:
val selectedData = selection.sorted.map(data)
UPDATED
In the spirit of finding all the possible algorithms, here's the version using collect:
val selectedData = data
.zipWithIndex
.collect {
case (item, index) if selection.contains(index) => item
}
The following is the probably most scalable way to do it in terms of efficiency, and unlike many answers on SO, actually follows the official scala style guide exactly.
import scala.collection.immutable.HashSet
val selectionSet = new HashSet() ++ selection
data.zipWithIndex.collect {
case (datum, index) if selectionSet.contains(index) => datum
}
If the resulting collection is to be passed to additional map, flatMap, etc, suggest turning data into a lazy sequence. In fact perhaps you should do this anyway in order to avoid 2-passes, one for the zipWithIndex one for the collect, but I doubt when benchmarked one would gain much.
There is actually an easier way to filter by index using the map method. Here is an example
val indices = List(0, 2)
val data = List("a", "b", "c")
println(indices.map(data)) // will print List("a", "c")