Compare a string with many values [duplicate] - jasper-reports

This question already has answers here:
Check if a value exists in ArrayList
(4 answers)
Closed 1 year ago.
I want to add the below condition with java in Ireport:
Field.equals("red" or "bleu" or "black" or "....") ? "yes" : "no"
Do I have to use
Field.equals("..")||$F{color}.equals("..")
I have a long list.
Is there any other way to express it?

Approach #1:
private static final HashSet<String> colors = new HashSet<>(
Arrays.asList("red", "blue", "black", "sky-blue pink"));
res = (colors.contains(field)) ? "yes" : "no";
Approach #2 (Java 7 and later)
switch (field) {
case "red": case "blue": case "black": case "sky-blue pink":
res = "yes";
break;
default:
res = "no";
}
Approach #3 (Java 12 or later)
res = switch (field) {
case "red", "blue", "black", "sky-blue pink" -> "yes";
default -> "no";
};
The performance of the three approaches should be about the same. Under the hood, string switch statements and switch expressions will typically use the equivalent of a static HashMap to map from the field value to either a value or a jump address. However, if performance really matters to you, benchmark the alternatives in the context of your application (after profiling, etc).
To my mind, the last approach is the neatest ... if you have the freedom to use Java 12+. The first approach has the possible advantage that the list of strings doesn't need to be hard-wired into your codebase.

Keep a list of all the strings that you want to compare Field against
List<String> list = Arrays.asList("red","blue","green");
return list.contains(field) ? "yes" : "no";

Here is another way:
public class Main
{
public static void main(String[] args) {
String field = "brown";
switch(field) {
case "blue":
case "black":
case "red":
case "yellow":
System.out.println("Color :"+field);
break;
default:
System.out.println("Not found");
}
}
}

Related

How to change a list to lower case? Keep getting error in for loop

This is the code I have for an exercise on exercism. I want to change the colours typed to lower case just to be sure there won't be any errors. But the way I have now gives me an error on the for loop "the typed string used in the for loop must implement iterable dart". Help?
void main(){
ResistorColorDuo obj = new ResistorColorDuo();
obj.result(['Orange','Black']); //I want something that would make these colours lower case so there's no error if someone types it with upper case
}
class ResistorColorDuo {
static const COLOR_CODES = [
'black', 'brown', 'red', 'orange', 'yellow', 'green', 'blue', 'violet', 'grey', 'white',];
void result(List<String> givenColors) {
String numbers = '';
for (var color in givenColors.toString().toLowerCase()) {//But this throws an error "the type string used in the for loop must implement iterable dart"
numbers = numbers + COLOR_CODES.indexOf(color).toString();
}
if (givenColors.length != 2)
print ('ERROR: You should provide exactly 2 colors');
else
print (int.parse(numbers));
}
}
Here is the answer.
Your mistake was here givenColors.toString().toLowerCase() the givenColors() is a list and list can't be converted to string as you are giving in a for loop. In the below code we take a single value from the list and then convert to the lower case.
This line color.toLowerCase() converts the value to the lower case as color contains a single value from the list on each iteration.
Updated Code
void main(){
ResistorColorDuo obj = new ResistorColorDuo();
obj.result(['Orange','Black']); //I want something that would make these colours lower case so there's no error if someone types it with upper case
}
class ResistorColorDuo {
static const COLOR_CODES = [
'black', 'brown', 'red', 'orange', 'yellow', 'green', 'blue', 'violet', 'grey', 'white',];
void result(List<String> givenColors) {
String numbers = '';
for (var color in givenColors) {//But this throws an error "the type string used in the for loop must implement iterable dart"
numbers = numbers + COLOR_CODES.indexOf(color.toLowerCase()).toString();
}
if (givenColors.length != 2)
print ('ERROR: You should provide exactly 2 colors');
else
print (int.parse(numbers));
}
}
givenColors.toString() converts your list to String; so it can't be iterated;
There are few solutions you can take;
List colorsLowercase = [];
for (var color in givenColors) {
colorsLowercase.add(color.toLowerCase())
...
}
Or like #pskink suggested
givenColors.map((c) => c.toLowerCase())

From RxJava2, How can I compare and filter two observables if the values are equal?

I am new to RxJava2.
I am trying to get a list of Transaction object both from cache and from server.
I want to compare the server value to cache value and if the server value is the same, then ignore it.
I was able to do it easily using .scan() because we can return null and when null is returned from the .scan() the value got ignored(filtered).
RxJava 1
private Observable<List<Transaction>> getTransactionsFromCacheAndServer() {
return Observable.concat(
getTransactionsFromCache(),
getTransactionsFromServer()
)
.scan((p1, p2) -> {
if (p1 == null && p2 != null) {
return p2;
} else if (p1 != null && !isListSame(p1, p2)) {
return p2;
} else {
return null;
}
});
}
With RxJava 2, since I cannot return null anymore, things are not easy.
RxJava 2
private Observable<List<Transaction>> getTransactionsFromCacheAndServer() {
return Observable.concat(
getTransactionsFromCache(),
getTransactionsFromServer()
)
.map(FilterObject::new)
.scan((filterObject1, filterObject2) -> {
List<Transaction> p1 = (List<Transaction>)filterObject1.value;
List<Transaction> p2 = (List<Transaction>)filterObject2.value;
if (p1.size() == 0 && p2.size() > 0) {
return filterObject2;
} else if (!isListSame(p1, p2)) {
return filterObject2;
} else {
filterObject2.filter = true;
return filterObject2;
}
})
.filter(filterObject -> !filterObject.filter)
.map(filterObject -> (List<Transaction>)filterObject.value);
}
Where FilterObject is:
public class FilterObject {
public Object value;
public boolean filter;
public FilterObject(Object value) {
this.value = value;
}
}
Even though I can achieve the same thing using above method, it seems very ugly. Also I had to include two maps which might not be so performance friendly.
Is there a simple/clean way to achieve what I want?
I don't think there is a generic solution to this problem, since an empty list and a list that needs to be filtered (which happens to be empty in all cases) are two different things (the output of the scan) and needs to be handled differently.
However, in your particular case you never emit an empty list, except maybe for the first output.
(I am using String instead Transaction, shouldn't matter)
private Observable<List<String>> getTransactionsFromCacheAndServer() {
return Observable.concat(
getTransactionsFromCache(),
getTransactionsFromServer()
)
.filter(list -> !list.isEmpty())
// If you prefer a consistent empty list over the first
// empty list emission getting filtered
.startWith((List<String>) Collections.EMPTY_LIST)
// Newly emitted value cannot be empty, it only depends only on the comparison
.distinctUntilChanged(this::isListSame);
}
That's the closest I could get with as few operators as possible. Hope it solves your problem.
Based on andras' answer, I modified little bit to achieve what I want.
private Observable<List<String>> getTransactionsFromCacheAndServer() {
return Observable.concat(
getTransactionsFromCache(),
getTransactionsFromServer()
)
.filter(list -> !list.isEmpty())
.distinctUntilChanged(this::isListSame)
.switchIfEmpty(Observable.just(new ArrayList<>()));
}
Andreas' answer will always receive an empty list and then a real data.
My solution above will receive:
1. Data from cache (and then data from server if different)
2. Empty list if both cache and server returns Empty list.

Switch Statement for Field Value

I am trying to set up a customization that will dynamically display values in a series of fields using a switch statement.
If we focus on one field I have a String List
public static class SMSPlans
{
public const string A = "A";
public const string B = "B";
public const string C = "C";
public const string Z = "Z";
}
[PXDBString(2, IsUnicode = true)]
[PXDefault(SMSPlans.Z)]
[PXUIField(DisplayName = "SMS Plan Selected")]
[PXStringList(
new string[]
{
SMSPlans.A,
SMSPlans.B,
SMSPlans.C,
SMSPlans.Z
},
new string[]
{
"Plan A",
"Plan B",
"Plan C",
"No Text Plan"
})]
I would like to when this field is set to any one of the allowable values populate a series of fields with corresponding fixed values as shown in the image below (0 is default value currently would show up if any plan is selected)
I planned on using the formula functions and using a switch statement to set my desired value that would look like
[PXFormula(null,typeof(Switch<Case<Where<Current<UsrMPSMSPlanSelected, Equal<SMSPlans.A>>,0>))]
I am stuck however on:
How I need to use the _RowSelect() or other event handlers
What if any value would be stored in the database for these fields assigned by the switch statment
finally is this switch structured correctly as it is not currently working
From what I can tell you have a few ways to handle this.
1) With PXFormula attribute tags - your Switch definition is mostly correct in the sample above but depending on where you have it the PXFormula definition itself is incorrect. What I would do is put the PXFormula tag on the fields that need to be updated.
For example, if your field is UsrMinText use the following:
[PXFormula(typeof(Switch<Case<Where<UsrMPSMSPlanSelected,Equal<SMSPlans.A>>,{value if true},{value if false or more case statements}))]
2) Personally for this type of customization I would use an actual event method in the BLC to do this. A good example of this is in the help guide for the events.
protected void Batch_ManualStatus_FieldUpdating(PXCache sender, PXFieldUpdatingEventArgs e)
{
Batch batch = (Batch)e.Row;
if (batch != null && e.NewValue != null)
{
switch ((string)e.NewValue)
{
case "H":
batch.Hold = true;
batch.Released = false;
batch.Posted = false;
break;
case "B":
batch.Hold = false;
batch.Released = false;
batch.Posted = false;
break;
case "U":
batch.Hold = false;
batch.Released = true;
batch.Posted = false;
break;
case "P":
batch.Hold = false;
batch.Released = true;
batch.Posted = true;
break;
}
}
}
In either method, the value that will be stored in the database is whatever you specify in either the {True}/{False} values for PXFormula or the values specified in the actual switch methods.
One thing to remember is field order in the DACS is important. I'd read through the training information and help guides for more information on this.

MongoDB - combining multiple Numeric Range queries (C# driver)

*Mongo Newbie here
I have a document containing several hundred numeric fields which I need to query in combination.
var collection = _myDB.GetCollection<MyDocument>("collection");
IMongoQuery mongoQuery; // = Query.GT("field", value1).LT(value2);
foreach (MyObject queryObj in Queries)
{
// I have several hundred fields such as Height, that are in queryObj
// how do I build a "boolean" query in C#
mongoQuery = Query.GTE("Height", Convert.ToInt16(queryObj.Height * lowerbound));
}
I have several hundred fields such as Height (e.g. Width, Area, Perimeter etc.), that are in queryObj how do I build a "boolean" query in C# that combines range queries for each field in conjunction.
I have tried to use the example Query.GT("field", value1).LT(value2);, however the compiler does not accept the LT(Value) construct. In any event I need to be able to build a complex boolean query by looping through each of the numeric field values.
Thanks for helping a newbie out.
EDIT 3:
Ok, it looks like you already have code in place to build the complicated query. In that case, you just needed to fix the compiler issue. Am assuming you want to do the following (x > 20 && x < 40) && (y > 30 && y < 50) ...
var collection = _myDB.GetCollection<MyDocument>("collection");
var queries = new List<IMongoQuery>();
foreach (MyObject queryObj in Queries)
{
//I have several hundred fields such as Height, that are in queryObj
//how do I build a "boolean" query in C#
var lowerBoundQuery = Query.GTE("Height", Convert.ToInt16(queryObj.Height * lowerbound));
var upperBoundQuery = Query.LTE("Height", Convert.ToInt16(queryObj.Height * upperbound));
var query = Query.And(lowerBoundQuery, upperBoundQuery);
queries.Add(query);
}
var finalQuery = Query.And(queries);
/*
if you want to instead do an OR,
var finalQuery = Query.Or(queries);
*/
Original Answer.
var list = _myDb.GetCollection<MyDoc>("CollectionName")
.AsQueryable<MyDoc>()
.Where(x =>
x.Height > 20 &&
x.Height < 40)
.ToList();
I have tried to use the example Query.GT("field", value1).LT(value2);,
however the compiler does not accept the LT(Value) construct.
You can query MongoDB using linq, if you are using the official C# driver. That ought to solve the compiler issue I think.
The more interesting question I have in mind is, how are you going to construct that complicated boolean query?
One option is to dynamically build an Expression and then pass that to the Where
My colleague is using the following code for something similar...
public static IQueryable<T> Where<T>(this IQueryable<T> query,
string column, object value, WhereOperation operation)
{
if (string.IsNullOrEmpty(column))
return query;
ParameterExpression parameter = Expression.Parameter(query.ElementType, "p");
MemberExpression memberAccess = null;
foreach (var property in column.Split('.'))
memberAccess = MemberExpression.Property
(memberAccess ?? (parameter as Expression), property);
//change param value type
//necessary to getting bool from string
ConstantExpression filter = Expression.Constant
(
Convert.ChangeType(value, memberAccess.Type)
);
//switch operation
Expression condition = null;
LambdaExpression lambda = null;
switch (operation)
{
//equal ==
case WhereOperation.Equal:
condition = Expression.Equal(memberAccess, filter);
lambda = Expression.Lambda(condition, parameter);
break;
//not equal !=
case WhereOperation.NotEqual:
condition = Expression.NotEqual(memberAccess, filter);
lambda = Expression.Lambda(condition, parameter);
break;
//string.Contains()
case WhereOperation.Contains:
condition = Expression.Call(memberAccess,
typeof(string).GetMethod("Contains"),
Expression.Constant(value));
lambda = Expression.Lambda(condition, parameter);
break;
}
MethodCallExpression result = Expression.Call(
typeof(Queryable), "Where",
new[] { query.ElementType },
query.Expression,
lambda);
return query.Provider.CreateQuery<T>(result);
}
public enum WhereOperation
{
Equal,
NotEqual,
Contains
}
Currently it only supports == && !=, but it shouldn't be that difficult to implement >= or <= ...
You could get some hints from the Expression class: http://msdn.microsoft.com/en-us/library/system.linq.expressions.expression.aspx
EDIT:
var props = ["Height", "Weight", "Age"];
var query = _myDb.GetCollection<MyDoc>("CName").AsQueryable<MyDoc>();
foreach (var prop in props)
{
query = query.Where(prop, GetLowerLimit(queryObj, prop), WhereOperation.Between, GetUpperLimit(queryObj, prop));
}
// the above query when iterated over, will result in a where clause that joins each individual `prop\condition` with an `AND`.
// The code above will not compile. The `Where` function I wrote doesnt accept 4 parameters. You will need to implement the logic for that yourself. Though it ought to be straight forward I think...
EDIT 2:
If you don't want to use linq, you can still use Mongo Query. You will just need to craft your queries using the Query.And() and Query.Or().
// I think this might be deprecated. Please refer the release notes for the C# driver version 1.5.0
Query.And(Query.GTE("Salary", new BsonDouble(20)), Query.LTE("Salary", new BsonDouble(40)), Query.GTE("Height", new BsonDouble(20)), Query.LTE("Height", new BsonDouble(40)))
// strongly typed version
new QueryBuilder<Employee>().And(Query<Employee>.GTE(x => x.Salary, 40), Query<Employee>.LTE(x => x.Salary, 60), Query<Employee>.GTE(x => x.HourlyRateToClients, 40), Query<Employee>.LTE(x => x.HourlyRateToClients, 60))

The 'ArrayIndex' LINQ expression node type is not supported by LINQ to Entities - using interface & ReportViewer

a quick question really.
I'm struggling to implement Linq2Entities statement that could take more than one value for a particular "field". I'm passing a number of strings to the getClientsProjected() I can easily compare single value. But I've got on my page multiple dropdown and out of that I get string separated with coma I then later use to split it to string[] e.g. __ACCOUNT_SITE = "1234,5678" (see the code below) I've tried for/foreach/contains none of which worked...
public IQueryable<ClientViewModel> getClientsProjected(string __ACCOUNT_SITE, string __ACCOUNT)
{
var projectedClients = from c in getClosedSRs()
select new ClientViewModel
{
_ACCOUNT_ID_CSR = c.ACCOUNT_ID_CSR,
_ACCOUNT = c.ACCOUNT,
_ACCOUNT_FAMILY = c.ACCOUNT_FAMILY,
...
...
_ACCOUNT_SITE = c.ACCOUNT_SITE
};
if (String.IsNullOrEmpty(__ACCOUNT) != true && __ACCOUNT != "ALL")
{
//this works fine as an __ACCOUNT is of a single value
projectedClients = projectedClients.Where(c => c._ACCOUNT == __ACCOUNT);
}
if (String.IsNullOrEmpty(__ACCOUNT_SITE) != true && __ACCOUNT_SITE != "ALL")
{
String[] splitSites = __ACCOUNT_SITE.Split(',');
//????????????????????????????????????????????????
}
return projectedClients;
}
Now, to most of you this will make complete sense. I've read many articles but did not find a proper answer. I however can't use Linq2SQL as already built my entire site using L2E, interface and ReportViewer.
Any workaround?
If you are trying to filter projectedClients based on the values in splitSites, then use:
if (String.IsNullOrEmpty(__ACCOUNT_SITE) != true && __ACCOUNT_SITE != "ALL")
{
String[] splitSites = __ACCOUNT_SITE.Split(',');
projectedClients = projectedClients.Where(x => splitSites.Contains(x._ACCOUNT);
}