I have two Sequences, say:
val first = Array("B", "L", "T")
val second = Array("T70", "B25", "B80", "A50", "M100", "B50")
How do I get a product such that elements of the first array are joined with each element of the second array which startsWith the former and also yield a default empty result when no element in the second array meets the condition.
Effectively to get an Output:
expectedProductArray = Array("B-B25", "B-B80", "B-B50", "L-Default", "T-T70")
I tried doing,
val myProductArray: Array[String] = for {
f <- first
s <- second if s.startsWith(f)
} yield s"""$f-$s"""
and i get:
myProductArray = Array("B-B25", "B-B80", "B-B50", "T-T70")
Is there an Idiomatic way of adding a default value for values in first sequence not having a corresponding value in the second sequence with the given criteria? Appreciate your thoughts.
Here's one approach by making array second a Map and looking up the Map for elements in array first with getOrElse:
val first = Array("B", "L", "T")
val second = Array("T70", "B25", "B80", "A50", "M100", "B50")
val m = second.groupBy(_(0).toString)
// m: scala.collection.immutable.Map[String,Array[String]] =
// Map(M -> Array(M100), A -> Array(A50), B -> Array(B25, B80, B50), T -> Array(T70))
first.flatMap(x => m.getOrElse(x, Array("Default")).map(x + "-" + _))
// res1: Array[String] = Array(B-B25, B-B80, B-B50, L-Default, T-T70)
In case you prefer using for-comprehension:
for {
x <- first
y <- m.getOrElse(x, Array("Default"))
} yield s"$x-$y"
There is a good question which says that we should Stream/View or Iterate our collections to make them on-demand. It is clear. I just do not understand what should I apply the .view or .iterate to in the following demo
val l1 = List("10", "00", "0")
def gen(depth: Int): Iterable[String] = if (depth == 1) l1 else {
for (sub <- gen(depth-1); item <- List(depth + sub, sub+sub, sub)) yield item
}
Should I apply them to gen(depth-1) or to List(depth+..)?
By the way, should I inline l1 in the (depth == 1) l1 else? It is not used anywhere else. I just afraid that it would create a new list for every leaf.
I would have to try it, but I would say List(depth+..).view, since you wont use the same values more than once.I think it will give you a sort of DFS traversal given the recursion you have there.
And yeah, I would not inline it but live l1 like that. I would even do val l1 = List("10", "00", "0").view.
Hi my two lists as follows:
val a = List((1430299869,"A",4200), (1430299869,"A",0))
val b = List((1430302366,"B",4100), (1430302366,"B",4200), (1430302366,"B",5000), (1430302366,"B",27017), (1430302366,"B",80), (1430302366,"B",9300), (1430302366,"B",9200), (1430302366,"A",5000), (1430302366,"A",4200), (1430302366,"A",80), (1430302366,"A",443), (1430302366,"C",4100), (1430302366,"C",4200), (1430302366,"C",27017), (1430302366,"C",5000), (1430302366,"C",80))
when I used zip two lists as below :
val c = a zip b
it returns results as
List(((1430299869,A,4200),(1430302366,B,4100)), ((1430299869,A,0),(1430302366,B,4200)))
Not all lists of tuples, how can I zip all above data?
EDIT
expected results as combine of two lists like :
List((1430299869,"A",4200), (1430299869,"A",0),(1430302366,"B",4100), (1430302366,"B",4200), (1430302366,"B",5000), (1430302366,"B",27017), (1430302366,"B",80), (1430302366,"B",9300), (1430302366,"B",9200), (1430302366,"A",5000), (1430302366,"A",4200), (1430302366,"A",80), (1430302366,"A",443), (1430302366,"C",4100), (1430302366,"C",4200), (1430302366,"C",27017), (1430302366,"C",5000), (1430302366,"C",80))
Second Edit
I tried this :
val d = for(((a,b,c),(d,e,f)) <- (a zip b)if(b.equals(e) && c.equals(f))) yield (d,e,f)
but it gives empty results because of (a zip b) but I replaced a zip b as a ++ b then it shows following error :
constructor cannot be instantiated to expected type;
So how can I get matching tuples?
Just add one list to another:
a ++ b
According to your 2nd edit, what you need is:
for {
(a1,b1,c) <- a //rename extracted to a1 and b1 to avoid confusion
(d,e,f) <- b
if b1.equals(e) && c.equals(f)
} yield (d,e,f)
Or:
for {
(a1, b1, c) <- a
(d, `b1`, `c`) <- b //enclosing it in backticks avoids capture and matches against already defined values
} yield (d, b1, c)
Zipping won't help since you need to compare all tuples in a with all tuples in b , it seems.
a zip b creates a list of pairs of elements from a and b.
What you're most likely looking for is list concatenation, which is a ++ b
On zipping (pairing) all data in the lists, consider first a briefer input for illustrating the case,
val a = (1 to 2).toList
val b = (10 to 12).toList
Then for instance a for comprehension may convey the needs,
for (i <- a; j <- b) yield (i,j)
which delivers
List((1,10), (1,11), (1,12),
(2,10), (2,11), (2,12))
Update
From OP latest update, consider a dedicated filtering function,
type triplet = (Int,String,Int)
def filtering(key: triplet, xs: List[triplet]) =
xs.filter( v => key._2 == v._2 && key._3 == v._3 )
and so apply it with flatMap,
a.flatMap(filtering(_, b))
List((1430302366,A,4200))
One additional step is to encapsulate this in an implicit class,
implicit class OpsFilter(val keys: List[triplet]) extends AnyVal {
def filtering(xs: List[triplet]) = {
keys.flatMap ( key => xs.filter( v => key._2 == v._2 && key._3 == v._3 ))
}
}
and likewise,
a.filtering(b)
List((1430302366,A,4200))
I can collect the results at the inner-most for body into a List[Output] and return them. But I want to use yield. How can this method be converted into using for-yield pattern:
def useForComprehension(input : Input): List[Output] = {
for (o <- splitInputIntoPieces(input)) {
for (restResults <- useForComprehension(subtract(input, o)) ) {
for (w <- f3(o)) {
yield w::restResults // !!!!! Error
}
}
}
}
In Scala, nested iteration is handled by adding additional <- clauses.
For example, let's say we have two lists l1 and l2 and we want generate over every pair of elements (x,y) where x is in l1 and y is in l2. The syntax in Scala is:
for { x <- l1
y <- l2
} yield (x,y)
When no yield keyword follows the for then the entire expression results in a type of Unit, which is the source of your type error. This is useful for performing side effects on the iteration, for example
for { x <- l1
y <- l2
} println((x,y))
For more information on for comprehensions see What is Scala's yield?
Your error may be because you are surrounding yield in {}.
for {stuff} {yield otherstuff}
The form should be:
for {stuff} yield otherstuff
You can of course replace "otherstuff" with a block if you want it to contain multiple expressions so you have:
for {stuff} yield {otherstuff}
Using your example I suspect you want something like:
def useForComprehension(input: Input): List[Output] =
for {
o <- splitInputIntoPieces(input)
restResults <- useForComprehension(subtract(input, o))
w <- f3(o)
} yield w :: restResults