Filter an Array using another Array - scala

val value = Array["id","sd","cd"] -- List of columns
val cols_list = Array["cd","id","tm","no","in","ts","nm"] - -- List of columns
i want a list with columns not in cols_list.
code i tried as below :
val newcol = for (x <- cols_list if x.toString.toUpperCase() not in value )
it's throwing error as value not is not a member of String.
is there a way that we can achieve?
Please suggest.

simplest is filterNot method (Apart from diff) that returns all elements from a list for which your function returns false.
val value = Array("id","sd","cd") // List of columns
val cols_list = Array("cd","id","tm","no","in","ts","nm")
val finallist = cols_list.filterNot(value.contains(_)) //cols_list.par.filterNot also you can use
println(finallist.mkString(" "))
}
Result : tm no in ts nm
How it works...
filter creates a collection with those elements that do not satisfy the predicate p and discarding the rest. This is collection level and will work for all Collections API in scala
signature :
def filterNot(p: (A) => Boolean): Collection[A]

use .diff to get list of columns not in cols_list
val value = Array("id","sd","cd")
val cols_list = Array("cd","id","tm","no","in","ts","nm")
value.diff(cols_list)
//Array[String] = Array(sd)
//case insensitive
value.map(x => x.toUpperCase).diff(cols_list.map(x => x.toUpperCase)).map(x => x.toLowerCase)
//Array[String] = Array(sd)
UPDATE:
cols_list.diff(value)
//Array[String] = Array(tm, no, in, ts, nm)
cols_list.map(x => x.toUpperCase).diff(value.map(x => x.toUpperCase)).map(x => x.toLowerCase)
//Array[String] = Array(tm, no, in, ts, nm)
cols_list.map(x => x.toUpperCase).diff(value.map(x => x.toUpperCase)).map(x => "\"a." + x.toLowerCase + "\"").mkString(",")
//String = "a.tm","a.no","a.in","a.ts","a.nm"

Related

Scala - functional methods - expected NotInferedA

I have to Strings which represent two html site contents. I want to remove whitespaces and comments, compute Levenshtein distance between them and on that basis I want to decide wether they are similiar or not.
I created functions:
val removeWhiteSpacesAndHtmlComments: String => String = _.replaceAll("\\s+","\\s").replaceAll("<!--.*?-->","")
val prepareContents: (String,String) => (String,String) = (s1,s2) => (removeWhiteSpacesAndHtmlComments.apply(s1), removeWhiteSpacesAndHtmlComments(s2))
val computeLevenshteinDistance:(String,String) => Int = StringUtils.getLevenshteinDistance(_,_)
val areContentsSimilarEnough: Int => Boolean = _ <= 50
I want to combine all those functions into a flow:
val isHtmlContentChanged: (String,String) => Boolean = prepareContents.tupled andThen computeLevenshteinDistance andThen areContentsSimilarEnough
Unfortunately over the computeLevenshteinDistance part I get exception:
Type mismatch, expected: (String,String) => NotInferedA, actual: (String,String)=>Int
How to solve this ?
Add .tupled to computeLevenshteinDistance.
Try it out!

Can I call a method inside of sortWith when sorting a sequence (or a map)?

I have a map Map[String,Option[Seq[String]]] and I have values for each of the string in a different map: Map[String,Option[Int]]. I am trying to map over the values and use a sortWith on the sequence but as I read online, I don't see any examples of having custom methods inside the sortWith.
How can I sort my sequence using sortWith? If I wanted to implement a custom method that returns a boolean to tell me what object is considered greater, is this possible?
val fieldMap = Map("user1" -> Seq("field1_name", "field2_name"), "user2" -> Seq("field3_name"))
val fieldValues = Map("field1_name" -> 2, "field2_name" -> 1, "field3_name" -> 3)
val sortedMap = fieldMap.mapValues(fieldList => fieldList.sortWith(fieldValues(_) < fieldValues(_)) // Scala doesn't like this
I tried:
fieldList.sortWith{(x,y) =>
val x = fieldValues(x)
val y = fieldValues(y)
x < y
}
This gives me a Type mismatch of expected type:
(String,String) => Boolean
and actual:
(String,String) => Any
EDIT Solution:
fieldList.sortWith{(x,y) =>
val x = fieldValues(x)
val y = fieldValues(x)
x.getOrElse[Double](0.0) < y.getOrElse[Double](0.0) // have to unwrap the Option.
}
You're using wrong syntax. For using sortWith you have to do something like:
fieldMap.mapValues(
fieldList => fieldList.sortWith(
(a,b) => fieldValues(a) > fieldValues(b)
)
)

How to create a List of Wildcard elements Scala

I'm trying to write a function that returns a list (for querying purposes) that has some wildcard elements:
def createPattern(query: List[(String,String)]) = {
val l = List[(_,_,_,_,_,_,_)]
var iter = query
while(iter != null) {
val x = iter.head._1 match {
case "userId" => 0
case "userName" => 1
case "email" => 2
case "userPassword" => 3
case "creationDate" => 4
case "lastLoginDate" => 5
case "removed" => 6
}
l(x) = iter.head._2
iter = iter.tail
}
l
}
So, the user enters some query terms as a list. The function parses through these terms and inserts them into val l. The fields that the user doesn't specify are entered as wildcards.
Val l is causing me troubles. Am I going the right route or are there better ways to do this?
Thanks!
Gosh, where to start. I'd begin by getting an IDE (IntelliJ / Eclipse) which will tell you when you're writing nonsense and why.
Read up on how List works. It's an immutable linked list so your attempts to update by index are very misguided.
Don't use tuples - use case classes.
You shouldn't ever need to use null and I guess here you mean Nil.
Don't use var and while - use for-expression, or the relevant higher-order functions foreach, map etc.
Your code doesn't make much sense as it is, but it seems you're trying to return a 7-element list with the second element of each tuple in the input list mapped via a lookup to position in the output list.
To improve it... don't do that. What you're doing (as programmers have done since arrays were invented) is to use the index as a crude proxy for a Map from Int to whatever. What you want is an actual Map. I don't know what you want to do with it, but wouldn't it be nicer if it were from these key strings themselves, rather than by a number? If so, you can simplify your whole method to
def createPattern(query: List[(String,String)]) = query.toMap
at which point you should realise you probably don't need the method at all, since you can just use toMap at the call site.
If you insist on using an Int index, you could write
def createPattern(query: List[(String,String)]) = {
def intVal(x: String) = x match {
case "userId" => 0
case "userName" => 1
case "email" => 2
case "userPassword" => 3
case "creationDate" => 4
case "lastLoginDate" => 5
case "removed" => 6
}
val tuples = for ((key, value) <- query) yield (intVal(key), value)
tuples.toMap
}
Not sure what you want to do with the resulting list, but you can't create a List of wildcards like that.
What do you want to do with the resulting list, and what type should it be?
Here's how you might build something if you wanted the result to be a List[String], and if you wanted wildcards to be "*":
def createPattern(query:List[(String,String)]) = {
val wildcard = "*"
def orElseWildcard(key:String) = query.find(_._1 == key).getOrElse("",wildcard)._2
orElseWildcard("userID") ::
orElseWildcard("userName") ::
orElseWildcard("email") ::
orElseWildcard("userPassword") ::
orElseWildcard("creationDate") ::
orElseWildcard("lastLoginDate") ::
orElseWildcard("removed") ::
Nil
}
You're not using List, Tuple, iterator, or wild-cards correctly.
I'd take a different approach - maybe something like this:
case class Pattern ( valueMap:Map[String,String] ) {
def this( valueList:List[(String,String)] ) = this( valueList.toMap )
val Seq(
userId,userName,email,userPassword,creationDate,
lastLoginDate,removed
):Seq[Option[String]] = Seq( "userId", "userName",
"email", "userPassword", "creationDate", "lastLoginDate",
"removed" ).map( valueMap.get(_) )
}
Then you can do something like this:
scala> val pattern = new Pattern( List( "userId" -> "Fred" ) )
pattern: Pattern = Pattern(Map(userId -> Fred))
scala> pattern.email
res2: Option[String] = None
scala> pattern.userId
res3: Option[String] = Some(Fred)
, or just use the map directly.

Initialize variables in one time with map containing nested IndexedSeq

I search of method to resolve this initialization problem of tuple () with result of a map, like this :
//My current state of cities
val listOfCity = IndexedSeq(new City1(), new City2())
// Function which compute my new state
val (newCity,exchange) = listOfCity.map{ city => computeNewCity(city,listOfCity)}
The variable newCity contain the result ._1 of my tuple returned by computeNewCity() and the variable exchange contain the result ._2 of the same tuple.
The function computeNewCity() return a new version of my object city and an history of exchange, results of my exchange with other cities in listOfCity, it's a tuple of type (City, Exchange)
How can i make this with help of functionnal programming ?
Thanks !
Sr
The problem is listOfCity.map{ city => computeNewCity(city,listOfCity)} returns an IndexedSeq[(City, Exchange)] (one tuple for each city in listOfCity), and obviously you can't just assign it to a (City, Exchange) tuple. You could take first element or last:
val (firstCity,exchange) = listOfCity.map{ city => computeNewCity(city,listOfCity)}.first
val (lastCity,exchange) = listOfCity.map{ city => computeNewCity(city,listOfCity)}.last
or get a tuple of two sequences (cities and their corresponding exchanges)
val (cities,exchanges) = listOfCity.map{ city => computeNewCity(city,listOfCity)}.unzip
Is this what you’re trying to do?
scala> val Seq(a, b) = IndexedSeq(IndexedSeq(3.0,2.0), IndexedSeq(1.0))
a: IndexedSeq[Double] = Vector(3.0, 2.0)
b: IndexedSeq[Double] = Vector(1.0)

Tune Nested Loop in Scala

I was wondering if I can tune the following Scala code :
def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] = {
var listNoDuplicates: List[(Class1, Class2)] = Nil
for (outerIndex <- 0 until listOfTuple.size) {
if (outerIndex != listOfTuple.size - 1)
for (innerIndex <- outerIndex + 1 until listOfTuple.size) {
if (listOfTuple(i)._1.flag.equals(listOfTuple(j)._1.flag))
listNoDuplicates = listOfTuple(i) :: listNoDuplicates
}
}
listNoDuplicates
}
Usually if you have someting looking like:
var accumulator: A = new A
for( b <- collection ) {
accumulator = update(accumulator, b)
}
val result = accumulator
can be converted in something like:
val result = collection.foldLeft( new A ){ (acc,b) => update( acc, b ) }
So here we can first use a map to force the unicity of flags. Supposing the flag has a type F:
val result = listOfTuples.foldLeft( Map[F,(ClassA,ClassB)] ){
( map, tuple ) => map + ( tuple._1.flag -> tuple )
}
Then the remaining tuples can be extracted from the map and converted to a list:
val uniqList = map.values.toList
It will keep the last tuple encoutered, if you want to keep the first one, replace foldLeft by foldRight, and invert the argument of the lambda.
Example:
case class ClassA( flag: Int )
case class ClassB( value: Int )
val listOfTuples =
List( (ClassA(1),ClassB(2)), (ClassA(3),ClassB(4)), (ClassA(1),ClassB(-1)) )
val result = listOfTuples.foldRight( Map[Int,(ClassA,ClassB)]() ) {
( tuple, map ) => map + ( tuple._1.flag -> tuple )
}
val uniqList = result.values.toList
//uniqList: List((ClassA(1),ClassB(2)), (ClassA(3),ClassB(4)))
Edit: If you need to retain the order of the initial list, use instead:
val uniqList = listOfTuples.filter( result.values.toSet )
This compiles, but as I can't test it it's hard to say if it does "The Right Thing" (tm):
def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] =
(for {outerIndex <- 0 until listOfTuple.size
if outerIndex != listOfTuple.size - 1
innerIndex <- outerIndex + 1 until listOfTuple.size
if listOfTuple(i)._1.flag == listOfTuple(j)._1.flag
} yield listOfTuple(i)).reverse.toList
Note that you can use == instead of equals (use eq if you need reference equality).
BTW: https://codereview.stackexchange.com/ is better suited for this type of question.
Do not use index with lists (like listOfTuple(i)). Index on lists have very lousy performance. So, some ways...
The easiest:
def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] =
SortedSet(listOfTuple: _*)(Ordering by (_._1.flag)).toList
This will preserve the last element of the list. If you want it to preserve the first element, pass listOfTuple.reverse instead. Because of the sorting, performance is, at best, O(nlogn). So, here's a faster way, using a mutable HashSet:
def removeDuplicates(listOfTuple: List[(Class1,Class2)]): List[(Class1,Class2)] = {
// Produce a hash map to find the duplicates
import scala.collection.mutable.HashSet
val seen = HashSet[Flag]()
// now fold
listOfTuple.foldLeft(Nil: List[(Class1,Class2)]) {
case (acc, el) =>
val result = if (seen(el._1.flag)) acc else el :: acc
seen += el._1.flag
result
}.reverse
}
One can avoid using a mutable HashSet in two ways:
Make seen a var, so that it can be updated.
Pass the set along with the list being created in the fold. The case then becomes:
case ((seen, acc), el) =>