How to compare dynamically in .NET Core - c#

This is the conditional rule configured in the database. The rules configured for each user are as follows。
| key | expression |rule|
|:---- |:--------------:|---:|
| 001 | >=500 and <=600| 1.2|
| 001 | >600 | 2.0|
| 002 | ==400 | 4.0|
| 002 | !=700 | 5.0|
| 003 | ==100 || ==200 | 0.5|
I need to get the conditional dynamic judgment that the key is 001
Below is my current code, I want generated C# code like this
if (item.TotalDaySam >= 500 && item.TotalDaySam <= 600)
{
// return Amount * 001 rule(1.2)
}
else if (item.TotalDaySam > 600)
{
// return Amount * 001 rule(2.0)
}
else
{
// retrun Amount
}
How do I get the configuration of the database to dynamically generate the judgment code to perform different logical calculations. I found a similar project RulesEngine, but I don't know how to implement it.

If you can store your data like this :
x>=500 && x<=600
x>600
x==600
x!=600
And then iterate foreach line replacing each time x by "item.TotalDaySam".
Finally you can find help from this post to parse the string into a if statement : C# Convert string to if condition
(sorry for the answer instead of comment I am not expert enough to have the right to comment ^^)

Related

UnionBy() EF Core

I have this ef query that give me the following result
IQueryable<A>
| Id | count |
| 1 | 5 |
| 2 | 6 |
IQueryable<B>
| Id | count |
| 1 | 1 |
| 2 | 2 |
| 3 | 9 |
When I do
IQueryable<Something> C = A.union(B)
Result that I got is this
| Id | count |
| 1 | 5 |
| 2 | 6 |
| 1 | 1 |
| 2 | 2 |
| 3 | 9 |
Whish is logical.
What I want is a UnionBy(Id)
IQueryable<Something> C = A.unionBy(B,c=>c.Id)
and this work perfectly in my case
| Id | count |
| 1 | 5 | -- FROM A
| 2 | 6 | -- FROM A
| 3 | 9 | -- FROM B
If the Query A or B are already executed by that I mean a ToList() was made it work perfectly and I have no problem in anyway.
But in my case, both queries are not executed and thus using this function result in.
System.InvalidOperationException query could not be translated.
the alternative is to use a GroupBy however I have no idea how to replacte UnionBy behavior with the GroupBy
FYI: the query works perfectly using the IQueryable.Union
and it's mandatory in my case that the request stay in IQueryable and not executed until later
UPDATE
⚠️ The solution that I'm looking for must stay in IQueryable without a toList() execution
"query could not be translated" usually means that EF doesn't support a certain LINQ or language construct as it can't translate it into SQL. One way to make this work is to force the evaluation of the expression client-side by adding e.g. ToList() or likes on the query parts before executing the UnionBy:
IQueryable<Something> C = A.ToList().UnionBy(B.ToList(),c=>c.Id);
The solution is simple you filtre A From B using the following
IQueryable<Something> C = A.Union(B.where(b=> A.All(a=>a.Id != b.Id))

Trim string in c# output last string

I'm currently making a Game and I have already split the string everything right but how I can trim the string and output the last line or a line in the middle?
Code:
text = "Username:King100 ID:100 Level:10";
string[] splittext = text.Split(' ');
foreach (var texs in splittext)
{
Console.WriteLine(texs);
}
Output:
Username:King100
ID:100
Level:10
I just want display the level 10 in the Console how thats works?
thanxs for helping.
Edit: the level can be changed often like 10 or 100 or 1000
Regex is more flexible solution. But if your text format is contsant, you can use this simple way:
string level = text.Substring(text.LastIndexOf(':') + 1);
You can also use a Regular Expression to solve this:
var regex = new Regex(#"Level:(?<Level>\d*)");
var matches = regex.Matches("Username:King100 ID:100 Level:10");
if (matches.Count > 0 && matches[0].Success)
{
Console.WriteLine(matches[0].Groups["Level"].Value);
}
var text = "Username:King100 ID:100 Level:10";
/*
Splits the given string on spaces and then splits on ":"
and creates a Dictionary ("Dictionary<TKey, TValue>")
*/
var dict = text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
.Select(part => part.Split(':'))
.ToDictionary(split => split[0], split => split[1]);
//If the dictionary count is greater than Zero
if(dict.Count > 0)
{
var levelValue = dict["Level"].ToString();
}
OK, because i'm annoying and totally bored of work, i decided to benchmark everyone's solutions.
The premise was simply to make an array of 1000 (scale) lines of strings (in the given format) with random positive int on the end;
Note : I made every solution int.Parse the result, as it seemed more useful
Mine
This just uses fixed, unsafe, pointers and no error checking
var level = 0;
fixed (char* pitem = item)
{
var len = pitem + item.Length;
for (var p = pitem ; p < len; p++)
if (*p >= '0' && *p <= '9')
level = level * 10 + *p - 48;
else
level = 0;
}
Results
Mode : Release
Test Framework : .NET Framework 4.7.1
Benchmarks runs : 1000 times (averaged)
Scale : 1,000
Name | Average | Fastest | StDv | Cycles | Pass | Gain
--------------------------------------------------------------------------
Mine | 0.095 ms | 0.085 ms | 0.01 | 317,205 | Yes | 96.59 %
Sanan | 0.202 ms | 0.184 ms | 0.02 | 680,747 | Yes | 92.75 %
Zaza | 0.373 ms | 0.316 ms | 0.10 | 1,254,302 | Yes | 86.60 %
Kishore | 0.479 ms | 0.423 ms | 0.06 | 1,620,756 | Yes | 82.81 %
Hussein | 1.045 ms | 0.946 ms | 0.11 | 3,547,305 | Yes | 62.50 %
Maccettura | 2.787 ms | 2.476 ms | 0.39 | 9,474,133 | Base | 0.00 %
Hardkoded | 6.691 ms | 5.927 ms | 0.67 | 22,750,311 | Yes | -140.09 %
Tom | 11.561 ms | 10.635 ms | 0.78 | 39,344,419 | Yes | -314.80 %
Summary
All the solutions do different things in different ways, comparing them is not really apples to apples.
Don't use mine, its totally unrealistic and only for fun. Use the version that makes the most sense to you, that is the most robust and easiest to maintain.
As always, regex is the slowest.
If level is always the last part of the string, and all you care about is the actual number, then you can just do:
var level = text.Split(':').LastOrDefault();
This would just split on ':' and give you the last (or default) element. Given your example input, level = "10".
Try this:
string input = "Username:King100 ID:100 Level:10";
Match m = Regex.Match(input, #"\s*Level:(?<level>\d+)");
if (m.Success&& m.Groups["level"].Success)
Console.WriteLine(m.Groups["level"].Value);
Also works for:
string input = "Username:King100 Level:10 ID:100";
string text = texs.Substring(texs.IndexOf("Level:")+6);
System.Console.WriteLine(text);

FIX Reading Repeating groups

I have a FIX log file. I'm iterating on the lines, putting each string into
Message m = new Message(str, false)
Because for some reason, validation fails on the file (even the first line). Now, I see that it's a 35=X type, and 268=4 (i.e. NoMDEntries=4, so I should have 4 groups in the message)
BUT, in the debug display I am not seeing any groups. m.base._groups has a count of 0.
The string in question is:
1128=9 | 9=363 | 35=X | 49=CME | 34=3151 | 52=20121216223556363 | 75=20121217 | 268=4 | 279=0 | 22=8 | 48=43585 | 83=902 | 107=6EH3 | 269=4 | 270=13186 | 273=223556000 | 286=5 | 279=0 | 22=8 | 48=43585 | 83=903 | 107=6EH3 | 269=E | 270=13186 | 271=9 | 273=223556000 | 279=0 | 22=8 | 48=43585 | 83=904 | 107=6EH3 | 269=F | 270=13185 | 273=223556000 | 279=1 | 22=8 | 48=43585 | 83=905 | 107=6EH3 | 269=0 | 270=13186 | 271=122 | 273=223556000 | 336=0 | 346=10 | 1023=1 | 10=179 |
Another thing is how do I read the groups? Instinctively, I want to do something like
for (int i = 1; i <= noMDEntries; i++) {
Group g = m.GetGroup(i);
int action = Int32.Parse(g.GetField(279));
....
}
But that's not how it works and I haven't found documentation with better explanations.
Thanks for the help,
Yonatan.
From your code snippets, I think you're using QuickFIX/n, the native C# implementation, so I will answer accordingly.
1) Your message construction is failing because you didn't provide a DataDictionary.
Use Message::FromString instead:
Message m = new Message();
m.FromString(msg_str, false, data_dic, data_dic, someMsgFactory);
Even better, use MarketDataIncrementalRefresh::FromString to get the right return type.
You can see some uses of this function here:
https://github.com/connamara/quickfixn/blob/master/UnitTests/MessageTests.cs
2) To read groups... well, QF/n has a doc page on that, which I think explains it pretty well.
http://quickfixn.org/tutorial/repeating-groups

Asserting very basic

I'm reading content from two files, now I want to test that content with my expected string.
string read1 = File.ReadAllText("#C:\somefile.txt");
string read2 = File.ReadAllText("#C:\somefilee.txt");
string expectedString = "blah";
Assert.AreEqual(read1 and read2 equals expected );
I know this is basic but I'm kinda stuck here.
You need to use 2 asserts, first to compare expected string with first file content, and then compare second file content with the first one (or with expected string once again), e.g.:
Assert.AreEqual(expectedString, read1, "File content should be equal to expected string");
Assert.AreEqual(read1, read2, "Files content should be identical");
Or you can use the condition
Assert.IsTrue(read1 == read2 == expectedString, "Files content should be equal to expected string");
But in this case you won't know what was the problem if the test fails.
I prefer to use plain C# to write such assertions, which you can with ExpressionToCode (nuget package). With that, your assertion would look as follows:
PAssert.That(
() => read1 == expectedString && read2 == expectedString
, "optional failure message");
On a failure, the library will include that expression in it's output, and include the actual values of the various variables (read1, read2, and expectedString) you've used.
For example, you might get a failure that looks as follows:
optional failure message
read1 == expectedString && read2 == expectedString
| | | | | | |
| | | | | | "blah"
| | | | | false
| | | | "Blah"
| | | false
| | "blah"
| true
"blah"
Disclaimer: I wrote ExpressionToCode.
Assert(read1 == read2 && read1 == expectedString, "Not all equal")
If I get you right, you want this:
try{
if(Assert.AreEqual(read1,read2,false)){
//do things
}
catch(AssertFailedException ex){
//assert failed
}
Look here for MSDN.

How to use C# to parse a glossary into database?

This should be a simple one, but I'm a beginner with C#.
Given a glossary list in the following format:
aptitude
ability, skill, gift, talent
aqueous
watery
arguably
maybe, perhaps, possibly, could be
How can I parse this, and insert into a database table in the format:
TABLE: Term_Glossary
================================================
Term_Name | Term_Definition |
================================================
aptitude | ability, skill, gift, talent |
------------------------------------------------
aqueous | watery |
------------------------------------------------
arguably | maybe, perhaps, possibly, could be|
================================================
Any help would be appreciated - thanks.
Update
I realize the database structure is simple/inefficient - but really, the point of my question is the code to parse the kind of text found in the first example, using C#. Thanks.
It may seem more complex at first, but you'll find it a lot easier in the long-term to think in terms of two tables:
===========================================
Term_ID | Term_Name |
===========================================
1 | aptitude |
2 | aqueous |
3 | arguably |
===========================================
===============================================
Definition_ID | Term_ID | Definition_Name |
===============================================
1 | 1 | ability |
2 | 1 | skill |
3 | 1 | gift |
4 | 1 | talent |
5 | 2 | watery |
6 | 3 | maybe |
7 | etc.etc.etc
Perhaps even think if you can normalise this further by having one table of words with IDs and a table of associations.
It looks to me like you would read the first line, save it to a variable, read the second line, save it to a second variable, then insert into the table where Term_Name = first variable, and Term_Definition = second variable.
So your logic would be like:
StreamReader SR;
string Term_Name;
string Term_Definition
SR = File.OpenText(filename);
Term_Name = SR.ReadLine();
while(Term_Name != null)
{
Term_Definition = SR.ReadLine();
// make your database call here to insert with these two variables. I don't know what DB you are using.
Term_Name = SR.ReadLine();
}
SR.Close();

Categories

Resources