I have a List with some properties and I would like two sort all of them by three properties. In my list I have number, number2, date and some other properties. When I click on number list sort by number ASC, when I click again on number list sort DESC by number. When I click again on number, do not sort by number. Same for number2 and date. But When I click on number and then on number2, sort by both fields. Same for date
I tried like this but does not work for me.
All fields are ASC order
reports.sort((a, b) => <Comparator<Reports>>[
(o1, o2) => o1.number.compareTo(o2.number),
(o1, o2) => o1.number2.compareTo(o2.number2),
(o1, o2) => o1.date.compareTo(o2.date),
].map((e) => e(a, b)).firstWhere((e) => e != 0, orElse: () => 0));
Number field is DASC order other are ASC order
reports.sort((a, b) => <Comparator<Reports>>[
(o1, o2) => o2.number.compareTo(o1.number),
(o1, o2) => o1.number2.compareTo(o2.number2),
(o1, o2) => o1.date.compareTo(o2.date),
].map((e) => e(a, b)).firstWhere((e) => e != 0, orElse: () => 0));
Tried like this but does not work. If anyone have idea please help.
Related
Can anyone point me at the faux pas in this EF Core query?
var employers = await iqDbContext.Payrolls
.GroupBy(p => p.PayeScheme.Employer, p => p)
.Select(group => new EmployerViewModel
{
Id = group.Key.Id,
Name = group.Key.Name
})
.ToListAsync();
throws:
System.InvalidOperationException: The LINQ expression 'DbSet<Payroll>()
.Join(
inner: DbSet<PayeScheme>(),
outerKeySelector: p => EF.Property<Nullable<int>>(p, "PAYR_fk1_PAYE_SCHEME"),
innerKeySelector: p0 => EF.Property<Nullable<int>>(p0, "Id"),
resultSelector: (o, i) => new TransparentIdentifier<Payroll, PayeScheme>(
Outer = o,
Inner = i
))
.Join(
inner: DbSet<Employer>(),
outerKeySelector: p => EF.Property<Nullable<int>>(p.Inner, "PychFk1Employer"),
innerKeySelector: e => EF.Property<Nullable<int>>(e, "Id"),
resultSelector: (o, i) => new TransparentIdentifier<TransparentIdentifier<Payroll, PayeScheme>, Employer>(
Outer = o,
Inner = i
))
.Where(p => p.Inner != null && __accessiblePayrollIds_0.Contains(p.Outer.Outer.Id))
.GroupBy(
keySelector: p => p.Inner,
elementSelector: p => p.Outer.Outer)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?
If you need correct grouping, you have to specify which columns to group, not whole object.
var employers = await iqDbContext.Payrolls
.GroupBy(p => new { p.PayeScheme.Employer.Id, p.PayeScheme.Employer.Name })
.Select(group => new EmployerViewModel
{
Id = group.Key.Id,
Name = group.Key.Name,
})
.ToListAsync();
var baseQuery = Context.Questions.AsNoTracking().Where(x => x.Active && x.QuestionFoils.Any());
// Gets 30
baseQuery = baseQuery.Where(x => x.QuestionReferences.Any());
//Gets 2
baseQuery = baseQuery.Where(
x => x.QuestionReferences.Any(qr =>
listNames.Any(name =>
name.FirstName == qr.Reference.ReferenceProfessors.Professor.FirstName &&
name.LastName == qr.Reference.ReferenceProfessors.Professor.LastName
)));
countCount = baseQuery.Count();
When I try to do any operation on the query, it gives a InvalidOperationException: The LINQ expression '' could not be translated.
InvalidOperationException: The LINQ expression
'Any, ReferenceProfessor>, Professor>>( source:
LeftJoin, ReferenceProfessor>, Professor, Nullable,
TransparentIdentifier, ReferenceProfessor>, Professor>>( outer:
LeftJoin,
ReferenceProfessor, Nullable,
TransparentIdentifier, ReferenceProfessor>>( outer: Join, TransparentIdentifier>( outer: Where( source:
DbSet, predicate: (q2) =>
Property>(EntityShaperExpression: EntityType: Question
ValueBufferExpression: ProjectionBindingExpression:
EmptyProjectionMember IsNullable: False , "QuestionId") ==
Property>(q2, "QuestionId")), inner: DbSet,
outerKeySelector: (q2) => Property>(q2, "ReferenceId"),
innerKeySelector: (r) => Property>(r, "ReferenceId"),
resultSelector: (o, i) => new TransparentIdentifier( Outer = o, Inner = i )), inner: DbSet,
outerKeySelector: (q2) => Property>(q2.Inner,
"ReferenceId"), innerKeySelector: (r0) => Property>(r0,
"ReferenceId"), resultSelector: (o, i) => new
TransparentIdentifier, ReferenceProfessor>( Outer = o, Inner = i )), inner:
DbSet, outerKeySelector: (q2) =>
Property>(q2.Inner, "ProfessorId"), innerKeySelector:
(p) => Property>(p, "ProfessorId"), resultSelector: (o,
i) => new
TransparentIdentifier, ReferenceProfessor>, Professor>( Outer = o, Inner = i )),
predicate: (q2) => Any( source: (Unhandled parameter:
__listNames_0), predicate: (name) => name.FirstName == q2.Inner.FirstName && name.LastName == q2.Inner.LastName))' could not
be translated. Either rewrite the query in a form that can be
translated, or switch to client evaluation explicitly by inserting a
call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or
ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for
more information.
Anything with a single table works just fine:
baseQuery = baseQuery.Where(x => x.QuestionCourses.Any(qc => courses.Any(name => name == qc.Course.Name)));
How would I rewrite the following to not throw this error?
x => x.QuestionReferences.Any(qr =>
listNames.Any(name =>
name.FirstName == qr.Reference.ReferenceProfessors.Professor.FirstName &&
name.LastName == qr.Reference.ReferenceProfessors.Professor.LastName
))
I believe the issue will be that you are trying to filter the Linq expression with an object with 2 fields (name.FirstName & name.LastName) which won't translate down to SQL. EF can translate list contains/any into IN clauses, but against a singular field/expression.
What should work:
Combine your names into a single list of strings. For instance "FirstName LastName" or "LastName, FirstName" then combine the professor name when comparing:
x => x.QuestionReferences.Any(qr =>
listNames.Any(name => name == qr.Reference.ReferenceProfessors.Professor.FirstName
+ " " + qr.Reference.ReferenceProfessors.Professor.LastName ))
Where listNames = "FirstName LastName";
I have a Slick query with two left joins (which end up as a Rep[Option[...]]) and column maps. I need to filter (using like) on the results. A row has to be included in the results if any of three columns match the like criteria, so I can't pre-filter the tables - I have to filter the resulting join, Rep[Option]s and all.
I can't figure how to filter the Rep[Option[String]] columns. The below code does not compile due to "cannot resolve symbol ||" - if compiles perfectly when I remove the Rep[Option] columns.
val joinedTable = Sites.map(s=>(s.id, s.gisId))
.joinLeft(SiteText.filter(_.lang==="jp").map(l=>(l.name, l.siteId))).on{ case(s,t)=>s._1===t._2 }
.joinLeft(SiteText.filter(_.lang==="en").map(l=>(l.name, l.siteId))).on{ case(st,t)=>st._1._1===t._2 }
val searchedTable = joinedTable.filter { row =>
List(
searchStr.map( t => row._1._1._2 like t ),
searchStr.map( t => row._1._2.map(_._1 like t) ),
searchStr.map( t => row._2.map(_._1 like t) )
).collect({case Some(criteria) => criteria}).reduceLeftOption(_ || _).getOrElse(true: Rep[Boolean])
}
The following seems to work for me:
joinedTable
.filter({ case ((a, b), c) => List(
searchStr.map(t => (a._2 like t)),
searchStr.map(t => b.filter(_._1 like t).isDefined),
searchStr.map(t => c.filter(_._1 like t).isDefined)
)
.flatten
.reduceLeftOption(_ || _)
.getOrElse(false: Rep[Boolean])
})
This are two sample entries from my RDD (RDD[(String, Map[String,List[Product wuth Serializable]])]):
(600,Map(current_data -> List((600,111,1,1), (615,111,1,5)), additional_data -> List((3,120,1,1,3370,f,0,268.78)))
(601,Map(current_data -> List((600,111,1,1), (615,111,1,5)), additional_data -> List((3,110,1,0,3370,f,0,268.78)))
I want to filter out entries that in the sub-list accessed by "additional_data" contain 0 in the 3rd field.
For instance, in the above example the list List((3,110,1,0,3370,f,0,268.78)) contains 0 in the 3rd field. Therefore the whole entry should be deleted and result is:
(600,Map(current_data -> List((600,111,1,1), (615,111,1,5)), additional_data -> List((3,120,1,1,3370,f,0,268.78)))
This is my current code, which does not compile because of the error Type mismatch, expected ((String,List[Product with Serializable])) => Boolean, actual ((String,List[Product with Serializable])) => Any.
val result = myRDD.filter({
case (id, list) => !list.exists({
t => (t.get("additional_data").map(_._3) == 0)
})
})
UPDATE:
My final attempt is the foolowing. It can be compiled, but does not solve the task for some reason. I checked that l.productElement(3) is really equal to 0 for some entries, but these entries are not deleted...:
val result = myRDD.filter{
case (id, hmap) => !hmap.get("member_data").exists({
t => (t.exists({ l => l.productElement(3).equals(0)}))
})
}
I belive you should change you code this way
val result = myRDD.filter{
case (id, map) => !map.get("additional_data").map(_._3).exists(_==0)
}
Suppose, I have a list of Students. Students have fields like name, birth date, grade, etc. How would you find Students with the best grade in Scala?
For example:
List(Student("Mike", "A"), Student("Pete", "B"), Student("Paul", A))"
I want to get
List(Student("Mike", "A"), Student("Paul", A))
Obviously, I can find the max grade ("A" in the list above) and then filter the list
students.filter(_.grade == max_grade)
This solution is O(N) but runs over the list twice. Can you suggest a better solution?
Running over the list twice is probably the best way to do it, but if you insist on a solution that only runs over once, you can use a fold (here works on empty lists):
(List[Student]() /: list){ (best,next) => best match {
case Nil => next :: Nil
case x :: rest =>
if (betterGrade(x,next)) best
else if (betterGrade(next,x)) next :: Nil
else next :: best
}}
If you are unfamiliar with folds, they are described in an answer here. They're a general way of accumulating something as you pass over a collection (e.g. list). If you're unfamiliar with matching, you can do the same thing with isEmpty and head. If you want the students in the same order as they appeared in the original list, run .reverse at the end.
Using foldLeft you traverse the list of students only once :
scala> students.foldLeft(List.empty[Student]) {
| case (Nil, student) => student::Nil
| case (list, student) if (list.head.grade == student.grade) => student::list
| case (list, student) if (list.head.grade > student.grade) => student::Nil
| case (list, _) => list
| }
res17: List[Student] = List(Student(Paul,A), Student(Mike,A))
There are already 6 answers, but I still feel compelled to add my take:
case class Lifted(grade: String, students: List[Student]) {
def mergeBest(other: Lifted) = grade compare other.grade match {
case 0 => copy(students = other.students ::: students)
case 1 => other
case -1 => this
}
}
This little case class will lift a Student into an object that keeps track of the best grade and a list cell containing the student. It also factors out the logic of the merge: if the new student has
the same grade => merge the new student into the result list, with the shorter one at the front for efficiency - otherwise result won't be O(n)
higher grade => replace current best with the new student
lower grade => keep the current best
The result can then be easily constructed with a reduceLeft:
val result = {
list.view.map(s => Lifted(s.grade, List(s)))
.reduceLeft((l1, l2) => l1.mergeBest(l2))
.students
}
// result: List[Student] = List(Student(Paul,A), Student(Mike,A))
PS. I'm upvoting your question - based on the sheer number of generated response
You can use filter on the students list.
case class Student(grade: Int)
val students = ...
val minGrade = 5
students filter ( _.grade < minGrade)
Works just fine also for type String
After sorting, you can use takeWhile to avoid iterating a second time.
case class Student(grade: Int)
val list = List(Student(1), Student(3), Student(2), Student(1), Student(25), Student(0), Student (25))
val sorted = list.sortWith (_.grade > _.grade)
sorted.takeWhile (_.grade == sorted(0).grade)
It still sorts the whole thing, even grades 1, 3, 0 and -1, which we aren't interested in, before taking the whipped cream, but it is short code.
update:
A second approach, which can be performed in parallel, is, to split the list, and take the max of each side, and then only the higher one, if there is - else both:
def takeMax (l: List[Student]) : List [Student] = l.size match {
case 0 => Nil
case 1 => l
case 2 => if (l(0).grade > l(1).grade) List (l(0)) else
if (l(0).grade < l(1).grade) List (l(1)) else List (l(0), l(1))
case _ => {
val left = takeMax (l.take (l.size / 2))
val right= takeMax (l.drop (l.size / 2))
if (left (0).grade > right(0).grade) left else
if (left (0).grade < right(0).grade) right else left ::: right }
}
Of course we like to factor out the student, and the method to compare two of them.
def takeMax [A] (l: List[A], cmp: ((A, A) => Int)) : List [A] = l.size match {
case 0 | 1 => l
case 2 => cmp (l(0), l(1)) match {
case 0 => l
case x => if (x > 0) List (l(0)) else List (l(1))
}
case _ => {
val left = takeMax (l.take (l.size / 2), cmp)
val right= takeMax (l.drop (l.size / 2), cmp)
cmp (left (0), right (0)) match {
case 0 => left ::: right
case x => if (x > 0) left else right }
}
}
def cmp (s1: Student, s2: Student) = s1.grade - s2.grade
takeMax (list, cmp)