I have the following filter on a List:
messages = messages.filterNot(m => m.room == room)
What I'm trying to do is have multiple arguments so I can match all items that have the same room ID and the same data value, so something like:
messages = messages.filterNot(m => m.room == room, m.data == data)
This doesnt work of course, is there a way I can do this?
Thanks in advance, any help much appreciated :)
You can deal with it
straightforward
messages.filterNot(m => m.room == room && m.data == data)
chaining filters
messages.filterNot(_.room == room).filterNot(_.data == data)
using WithFilter which applies restrictions on original collection instead of creating intermediate ones
messages.withFilter(_.room != room).withFilter(_.data != data) map identity
Related
I'm trying to use LinQ Intersect (or equivalent) into an IQueryable method but it seems like I'm doing it wrong.
I have some PRODUCTS that match some SPECIFITY (like colors, materials, height...), those specifications have different values, for example:
color : blue, red, yellow
height : 128cm, 152cm...
I need to get the products that match ALL the list of couple specifityId / specifityValue I provide.
Here what I'm trying to do:
// The list of couple SpecifityID (color, material..) / SpecifityValue (red, yellow, wood...)
List<string> SpecId_SpecValue = new List<string>();
SpecId_SpecValue.Add("3535a444-1139-4a1e-989f-795eb9be43be_BEA");
SpecId_SpecValue.Add("35ad6162-a885-4a6a-8044-78b68f6b2c4b_Purple");
int filterCOunt = SpecId_SpecValue.Count;
var query =
Products
.Include(pd => pd.ProductsSpecifity)
.Where(z => SpecId_SpecValue
.Intersect(z.ProductsSpecifity.Select(x => (x.SpecifityID.ToString() + "_" + x.SpecifityValue)).ToList()).Count() == filterCOunt);
I got the error : InvalidOperationException: The LINQ expression 'DbSet() 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/?linkid=2101038 for more information. which mean it can't be translated to SQL and I need to ToList before my filter.
The problem is, I don't want to call ToList() because I got huge number of products in my Database and I don't want to load them in memory before filtering them.
Is there an other way to achieve what I need to do?
I ended up using a solution found in the link #Gert Arnold provide here.
I used BlazarTech.QueryableValues.SqlServer #yv989c's answers
Here's what is now working like a charm :
// The list of couple SpecifityID (color, material..) / SpecifityValue (red, yellow, wood...)
Dictionary<Guid, string> SpecId_SpecValue = new Dictionary<Guid, string>();
SpecId_SpecValue.Add(new Guid("3535a444-1139-4a1e-989f-795eb9be43be"), "BEA");
SpecId_SpecValue.Add(new Guid("35ad6162-a885-4a6a-8044-78b68f6b2c4b"), "Purple");
// BlazarTech.QueryableValues.SqlServer
var queryableValues = DbContext.AsQueryableValues(SpecId_SpecValue);
var query = Products.Include(pd => pd.ProductsSpecifity)
.Where(x => x.ProductsSpecifity
.Where(e => queryableValues
.Where(v =>
v.Key == e.SpecifityID &&
v.Value == e.SpecifityValue
)
.Any()
).Count() == dynamicFilter.Count);
The query expresses "products of which all x.SpecifityID.ToString() + "_" + x.SpecifityValue combinations exactly match some given combinations".
Set combination operators like Except often don't play nice with EF for various reasons I'm not going into here. Fortunately, in many of these cases a work-around can be found by using Contains, which EF does support well. In your case:
var query = Products.Include(pd => pd.ProductsSpecifity)
.Where(z => z.ProductsSpecifity
.Select(x => x.SpecifityID.ToString() + "_" + x.SpecifityValue)
.Count(s => SpecId_SpecValue.Contains(s)) == filterCount);
Please note that the comparison is not efficient. Transforming database values before comparison disables any use of indexes (is not sargable). But doing this more efficiently isn't trivial in EF, see this.
I am trying to understand what is the best way to create a dynamic query.
I have a requirement where I will be writing an API to retrieve data from DB. the API has lot of filter paramters. eg. I need to retrieve movies that can be filtered on following properties.
MovieName, Genere, Rating, Language, Category
I can give these parameters in any combination.. so in my Data layer I started framing my dynamic query like this.
IQueryable<Movie> qryContext = null;
if(!string.isnullorEmpty(request.MovieName))
qryContext = context.Movies.Where(x => x.MovieName == request.MovieName)
if(!string.isnullorEmpty(request.Genere))
qryContext = context.Movies.Where(x => x.Genere == request.Genere)
if(!string.isnullorEmpty(request.Language))
qryContext = context.Movies.Where(x => x.Language == request.Language)
if(!string.isnullorEmpty(request.Category))
qryContext = context.Movies.Where(x => x.Category == request.Category)
if(qryContext!= null)
return qryContext.ToList();
else
return null;
Based on the given parameters, the sql query is framed..
But When I search in google reg dynamic queries in EF, most of the links refer to using Expression. Do I need to make use of Expression or can I proeeed with the above method.
Also let me know what advantage I get on using expressions.
Basically what you see inside the Where(...) is expression.
In your example this would be x => x.Language == request.Language
if(!string.isnullorEmpty(request.Language)) qryContext = context.Movies.Where(x => x.Language == request.Language)
Also, I would recommend you to take a look into the Dynamic expression library from EF Plus team. Here https://dynamic-linq.net/basic-simple-query
This allows you to pass expression as a string. And you can construct your filters in the Frontend, and pass them as a string, which helps you to write a much cleaner implementation of filters.
I have the following interval in my code, where I want to run some logic, however I need to do some queries before knowing if I can process the logic developed or not:
This is my observable:
const interval$ = Observable.interval(120000).startWith(0);
I need to map to this observable and only let it process if the return from a service call is not equal 1:
documentRepository.getProcedureLock().then(data => {
if (data !== null && data !=== '1') {
I have tried many things without success... the logic that process my interval is a .mergeMap and I don't have enough experience with it...can u guys help out?
See if that's what u looking for
Rx.Observable.fromPromise(documentRepository.getProcedureLock()).flatMap(data
=> {
if (data !== null && data !=== '1') return interval$
// i assume you want data if condition not met
return Rx.Observable.of(data)
}).subscribe(console.log)
for (String stock : allStocks) {
Quote quote = getQuote(...);
if (null == quoteLast) {
continue;
}
Price price = quote.getPrice();
if (null == price) {
continue;
}
}
I don't necessarily need a line by line translation, but I'm looking for the "Scala way" to handle this type of problem.
You don't need continue or breakable or anything like that in cases like this: Options and for comprehensions do the trick very nicely,
val stocksWithPrices =
for {
stock <- allStocks
quote <- Option(getQuote(...))
price <- Option(quote.getPrice())
} yield (stock, quote, price);
Generally you try to avoid those situations to begin with by filtering before you even start:
val goodStocks = allStocks.view.
map(stock => (stock, stock.getQuote)).filter(_._2 != null).
map { case (stock, quote) => (stock,quote, quote.getPrice) }.filter(_._3 != null)
(this example showing how you'd carry along partial results if you need them). I've used a view so that results will be computed as-needed, instead of creating a bunch of new collections at each step.
Actually, you'd probably have the quotes and such return options--look around on StackOverflow for examples of how to use those instead of null return values.
But, anyway, if that sort of thing doesn't work so well (e.g. because you are generating too many intermediate results that you need to keep, or you are relying on updating mutable variables and you want to keep the evaluation pattern simple so you know what's happening when) and you can't conceive of the problem in a different, possibly more robust way, then you can
import scala.util.control.Breaks._
for (stock <- allStocks) {
breakable {
val quote = getQuote(...)
if (quoteLast eq null) break;
...
}
}
The breakable construct specifies where breaks should take you to. If you put breakable outside a for loop, it works like a standard Java-style break. If you put it inside, it acts like continue.
Of course, if you have a very small number of conditions, you don't need the continue at all; just use the else of the if-statement.
Your control structure here can be mapped very idiomatically into the following for loop, and your code demonstrates the kind of filtering that Scala's for loop was designed for.
for {stock <- allStocks.view
quote = getQuote(...)
if quoteLast != null
price = quote.getPrice
if null != price
}{
// whatever comes after all of the null tests
}
By the way, Scala will automatically desugar this into the code from Rex Kerr's solution
val goodStocks = allStocks.view.
map(stock => (stock, stock.getQuote)).filter(_._2 != null).
map { case (stock, quote) => (stock,quote, quote.getPrice) }.filter(_._3 != null)
This solution probably doesn't work in general for all different kinds of more complex flows that might use continue, but it does address a lot of common ones.
If the focus is really on the continue and not on the null handling, just define an inner method (the null handling part is a different idiom in scala):
def handleStock(stock: String): Unit {
val quote = getQuote(...)
if (null == quoteLast) {
return
}
val price = quote.getPrice();
if (null == price) {
return
}
}
for (stock <- allStocks) {
handleStock(stock)
}
The simplest way is to embed the skipped-over code in an if with reversed-sense to what you have.
See http://www.scala-lang.org/node/257
I'll give some C-style "bracket" pseudo-code to show what I'd like to express in another way:
for (int i = 0; i < n; i++) {
if (i == 3 || i == 5 || i == 982) {
assertTrue( isCromulent(i) );
} else {
assertFalse( isCromulent(i) );
}
}
The for loop is not very important, that is not the point of my question: I'd like to know how I could rewrite what is inside the loop using Scala.
My goal is not to have the shortest code possible: it's because I'd like to understand what kind of manipulation can be done on method names (?) in Scala.
Can you do something like the following in Scala (following is still some kind of pseudo-code, not Scala code):
assert((i==3 || i==5 || i==982)?True:False)(isCromulent(i))
Or even something like this:
assertTrue( ((i==3 || i==5 || i==982) ? : ! ) isCromulent(i) )
Basically I'd like to know if the result of the test (i==3 || i==5 || i==982) can be used to dispatch between two methods or to add a "not" before an expression.
I don't know if it makes sense so please be kind (look my profile) :)
While pelotom's solution is much better for this case, you can also do this (which is a bit closer to what you asked originally):
(if (i==3||i==5||i==982) assertTrue else assertFalse)(isCromulent(i))
Constructing names dynamically can be done via reflection, but this certainly won't be concise.
assertTrue(isCromulent(i) == (i==3||i==5||i==982))
Within the Scala type system, it isn't possible to dynamically create a method name based on a condition.
But it isn't at all necessary in this case.
val condition = i == 3 || i == 5 || i == 982
assertEquals(condition, isCromulent(i))
I hope nobody minds this response, which is an aside rather than a direct answer.
I found the question and the answers so far very interesting and spent a while looking for a pattern matching based alternative.
The following is an attempt to generalise on this (very specific) category of testing:
class MatchSet(s: Set[Int]) {def unapply(i: Int) = s.contains(i)}
object MatchSet {def apply(s: Int*) = new MatchSet(Set(s:_*))}
val cromulentSet = MatchSet(3, 5, 982)
0 until n foreach {
case i # cromulentSet() => assertTrue(isCromulent(i))
case i => assertFalse(isCromulent(i))
}
The idea is to create ranges of values contained in MatchSet instances rather than use explicit matches.