We have the list like below
List:
(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))
As the number in the string may be referred by different elements, the expected result is:
("herry","0,1,2,3,6"), ("herry","4"), ("John","5")
I worked out solution using scala, but it looks complicated, is there a more clean and easy way to work out the result? Thanks in advance!
Here is my solution in scala,
val foo=List(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))
println(GetValue)
def GetValue()={
foo.zipWithIndex.map((tuple: ((String, String), Int)) =>{
val tuples = getrelated(tuple._1, foo)
(tuple._2, tuples)
}).map((tuple: (Int, List[(String, String)])) => tuple._2)
.map((tuples: List[(String, String)]) => (tuples.head._1,tuples.map((tuple: (String, String)) => tuple._2)))
.map((tuple: (String, List[String])) => (tuple._1, tuple._2.mkString(",").split(",").distinct.sorted.mkString(",")))
.distinct
}
def getrelated(start:(String,String),fooList:List[(String,String)]):List[(String,String)]={
val fooListWithout = fooList.filter((tuple: (String, String)) => tuple != start)
val result=fooListWithout
.filter((tuple: (String, String)) => findmatching(tuple._2,start._2))
.flatMap((tuple: (String, String)) => start :: getrelated(tuple,fooListWithout))
if (result.isEmpty)
List(start)
else
result
}
def findmatching(key1:String,key2:String)={
(key1.split(",")++key2.split(","))
.groupBy(identity)
.mapValues((strings: Array[String]) => strings.size)
.exists((tuple: (String, Int)) => tuple._2>1)
}
Let me clarify the algorithm
if the number list has the overlapping number, then group these number as one element
if the number list has no overlapping number, then consider it as independent element
for example,
input: List(("herry","0,1,2"),("herry","1,3"),("herry","7,4"),("herry","4"),("John","5"))
expected output: List(("herry","0,1,2,3" ), ("herry","4,7"), ("John","5"))
input: List(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))
expected: List("herry","0,1,2,3,6"), ("herry","4"), ("John","5")
input: List(("herry","0,1"),("herry","2,3"),("herry","3,6"),("herry","4"),("John","5"))
expected: List("herry","0,1"),("herry","2,3,6"), ("herry","4"), ("John","5")
My assumption is that tuples for the same key that contain multiple values should be aggregated. It is unclear what should happen in the same value appears singly and as part of a list, e.g. ("herry", "4"), ("herry, "1,4") however it should be simple enough to remove any such cases
val data = List(("herry","0,1,2"),("herry","1,3"),("herry","3,6"),("herry","4"),("John","5"))// Start writing your ScalaFiddle code here
val (singles, multiples) = data.partition{case (name, list) => !list.contains(",")}
val multiplesAggregated = multiples
.groupBy{case (key, _) => key)
.map{
case (key, values) =>
key -> values.flatMap{case (_, numbers) => numbers.split(",")}.distinct.sorted.mkString(",")}.toList
println(multiplesAggregated ++ singles)
Output:
List((herry,0,1,2,3,6), (herry,4), (John,5))
I have a problem in generating an Entity Framework query and not okay with linq style one :.....
This is my attempt:
var query = db.table
.Where(x => x.colA == 1)
.GroupBy(x => new {x.min,x.max})
.Select(y => if(y.key.min==0 && y.key.max==0)
{ " unchanged " }
else
{ y.key.min.tostring()+" "+y.key.max.tostring() })
.ToList()
I want to get "unchanged" string, if both value ofmin and max are zero, otherwise concat them
Use the conditional operator
// ...
.Select(y=> y.key.min==0 && y.key.max==0
? " unchanged "
: y.key.min.tostring()+" "+y.key.max.tostring())
// ...
Apparently all elements in your table have properties min and max
After GroupBy(x=> new {x.min,x.max}) you'll have a sequence of groups, where each group has a key {min, max}, all elements in the group have this value for their min and max properties.
After the GroupBy, you take every group, and from every group you'll select exactly one string. You get rid of the element of the group.
The string that you select depends on the key of the group: if the key = {0, 0} you select the string "unchanged", else you select the string:
y.key.min.tostring()+" "+y.key.max.tostring()
The result is a list of strings, something like:
"3 7",
"4 10,
"unchanged",
"2 8",
Are you sure you want this?
In that case you won't need the GroupBy. Distinct will be simpler and faster
List<string> result = db.table
.Where(tableRow => tableRow.colA == 1)
.Select(tableRow => tableRow.min==0 && tableRow.max==0
? " unchanged "
: tableRow.min.tostring()+" "+tableRow.max.tostring())
// from here you have a sequence of strings
// get rid of duplicates:
.Distinct()
.ToList();
For this specific case, you can use Conditional Operator (?:)
var query = db.table
.Where(x=> x.colA == 1)
.GroupBy(x=> new {x.min,x.max})
.Select(y=> (y.Key.min == 0 && y.Key.max == 0) ? " unchanged" : (y.Key.min.ToString()+" "+y.Key.max.ToString()))
.ToList();
Sorry I can't try it right now, but i think this should work
var query = db.table
.Where(x=> x.colA == 1)
.GroupBy(x=> new {x.min,x.max})
.Select(y=> {if(y.key.min==0 && y.key.max==0)
{
" unchanged "
} else
{
y.key.min.tostring()+" "+y.key.max.tostring();
} return y;})
.ToList()
I am currently learning Slick. I was trying to translate this query from SQL into Scala:
SELECT name FROM Passenger
WHERE ID_psg in
(SELECT ID_psg FROM Pass_in_trip
GROUP BY place, ID_psg
HAVING count(*)>1)
But I have only managed to write something like this, and it gives compile errors:
PassengerTable.table.filter(_.idPsg in (PassInTripTable.table.map(_.idPsgFk)))
.filter(PassengerTable.table.count(_.name) > 1)
.map(_.name)
I do not really know how to apply count and having on queries in Slick.
So I would be really grateful for some help.
Try
val subquery = PassInTripTable.table.groupBy(p => (p.place, p.idPsgFk))
.map { case ((place, id), group) => (id, group.length) }
.filter { case (id, count) => count > 1 }
.map { case (id, count) => id }
val query = PassengerTable.table.filter(_.idPsg in subquery).map(_.name)
val action = query.result
db.run(action)
http://slick.lightbend.com/doc/3.0.0/sql-to-slick.html#groupby
http://slick.lightbend.com/doc/3.0.0/sql-to-slick.html#subquery
http://slick.lightbend.com/doc/3.0.0/sql-to-slick.html#having
I'm trying to rewrite following SQL into slick:
SELECT id
SUM(
if (spend > 0, 1, 0)
)
FROM items
GROUP by id
My current code looks similar to this:
items.groupBy(r => r.id).map {
case (id, group) => (id, group.map { r => if (r.spend > 0) 1 else 0 }.sum)
}
But I got following error:
polymorphic expression cannot be instantiated to expected type;
found : [R]slick.lifted.Rep[R]
required: Boolean
I also tried to use filter and length, but with no success. How can I achieve my goal?
Slick already provides solution for this (documentation):
items.groupBy(r => r.id).map {
case (id, group) => (id, group.map { r =>
Case If r.spend > BigDecimal(0.0) Then 1 Else 0
}.sum)
}
Scala ternary expression could not be transferred to slick syntax.
Simplest approach is just to simplify the query here to
SELECT COUNT(id)
FROM items
WHERE spend > 0
GROUP by id
Corresponding slick will be
items.filter(_.spend > 0).groupBy(_.id) map {
case (id, group) => (id, group.size)
}
Or you could try to get access to the if function using SimpleFunction:
def ifFun[T] = SimpleFunction.ternary[Boolean, T, T, T]("if")
items.groupBy(_.id) map {
case (id, group) => (id, group.map(r => ifFun(r.spend > 0, 1, 0)).sum)
}
Given tables of:
case class Person(id: Int, name: String)
case class Dead(personId: Int)
and populated with:
Person(1, "George")
Person(2, "Barack")
Dead(1)
is it possible to have a single query that would produce a list of (Person, Option[Dead]) like so?
(Person(1, "George"), Some(Dead(1)))
(Person(2, "Barack"), None)
For slick 3.0 it should be something like this:
val query = for {
(p, d) <- persons joinLeft deads on (_.id === _.personId)
} yield (p, d)
val results: Future[Seq[(Person, Option[Dead])]] = db.run(query.result)
In slick, outer joins are automatically wrapped in an Option type. You can read more about joining here: http://slick.typesafe.com/doc/3.0.0/queries.html#joining-and-zipping