How to convert this to Linq? - linq

I got another Linq problem.. Because I'm not really sure if there is another way to do this. Here is what I want to convert:
class ID
{
public string name {get; set;}
public int id {get; set;}
}
ID[] num1 = new ID[2] { {"david",1} , {"mark",2} };
ID[] num2 = new ID[3] { {"david",1} , {"david",2} };
for(int i = 0; i < num1.Length; i++)
{
for(int j = 0; j < num2.Length; j++)
{
if(num1.name.Equals(num2.name) && num1.num == num2.num)
{
Console.Writeline("name: " + num1.name + " id: " + num1.id);
//Do something
break; //to avoid useless iterations once found
}
}
}
It's not a perfect code, but hopefully it captures what I want to do. Currently I am implementing this in Linq like such:
var match =
from a in num1
from b in num2
where (a.name.Equals(b.name) && a.num == b.num)
select a;
//do something with match
I'm pretty new to Linq so I'm not sure if this is the best way to do it or is there a much more "simpler" way. Since it seems like I'm just converting it to linq but essentially does the same code.
Thank you!

The Linq code you wrote is already on the right track to solve the problem, though it is not the only way to solve it.
Instead of using a where clause, you could override the Equals method on the class, or implement an IEqualityComaprer<Number>. Then you could use the Intersect Linq method.
Something like this:
public class Number
{
public override bool Equals(object other)
{
var otherAsNumber = other as Number;
return otherAsNumber != null
&& (otherAsNumber.Name == null
? this.Name == null
: otherAsNumber.Name.Equals(this.Name)
)
&& otherAsNumber.Num == this.Num
;
}
// ...
}
// ...
var result = num1.Intersect(num2);
foreach(var item in result)
{
// Do something
}
This of course assumes that you've fixed your code so that it compiles, and so that num1 and num2 refer to collections of Number classes, instead of individual Number instances. There are a lot of problems in the code you wrote, so I'll leave fixing that problem to you.

Related

Code Rewite for tuple and if else statements by using LINQ

In my C# application i am using linq. I need a help what is the syntax for if-elseif- using linq in single line. Data, RangeDate are the inputs. Here is the code:
var Date1 = RangeData.ToList();
int record =0;
foreach (var tr in Date1)
{
int id =0;
if (tr.Item1 != null && tr.Item1.port != null)
{
id = tr.Item1.port.id;
}
else if (tr.Item2 != null && tr.Item2.port != null)
{
id = tr.Item2.port.id;
}
if (id >0)
{
if(Data.Trygetvalue(id, out cdat)
{
// Do some operation. (var cdata = SumData(id, tr.item2.port.Date)
record ++;
}
}
}
I think your code example is false, your record variable is initialized to 0 on each loop so increment it is useless .
I suppose that you want to count records in your list which have an id, you can achieve this with one single Count() :
var record = Date1.Count(o => (o.Item1?.port?.id ?? o.Item2?.port?.id) > 0);
You can use following code:
var count = RangeData.Select(x => new { Id = x.Item1?.port?.id ?? x.Item2?.port?.id ?? 0, Item = x })
.Count(x =>
{
int? cdate = null; // change int to your desired type over here
if (x.Id > 0 && Data.Trygetvalue(x.Id, out cdat))
{
// Do some operation. (var cdata = SumData(x.Id, x.Item.Item2.port.Date)
return true;
}
return false;
});
Edit:
#D Stanley is completely right, LINQ is wrong tool over here. You can refactor few bits of your code though:
var Date1 = RangeData.ToList();
int record =0;
foreach (var tr in Date1)
{
int? cdat = null; // change int to your desired type over here
int id = tr.Item1?.port?.id ?? tr.Item2?.port?.id ?? 0;
if (id >0 && Data.Trygetvalue(id, out cdat))
{
// Do some operation. (var cdata = SumData(id, tr.Item2.port.Date)
record ++;
}
}
Linq is not the right tool here. Linq is for converting or querying a collection. You are looping over a collection and "doing some operation". Depending on what that operation is, trying to shoehorn it into a Linq statement will be harder to understand to an outside reader, difficult to debug, and hard to maintain.
There is absolutely nothing wrong with the loop that you have. As you can tell from the other answers, it's difficult to wedge all of the information you have into a "single-line" statement just to use Linq.

Best way to refactor current method

I tried really hard to refactor this code , but was unsuccessful. Please tell me how to go about it. I have been there for hours trying to find solution . I have read some excerpts from book Clean code however, being a beginner I really find it hard to refactor. Sorry, this is my first honest attempt but I am not able to figure out how to make this funtion of size ~4 or small.
public boolean[] validateTrueFalse(String[] checkBoxValues) {
boolean[] answer = new boolean[checkBoxValues.length];
for (int i = 0; i < checkBoxValues.length; i++) {
// values are like 1_true
String[] values = checkBoxValues[i].split("_"); // split each value
// from my array
int configId = Integer.parseInt(values[0]);
boolean isAns = Boolean.parseBoolean(values[1]);
for (TrueFalseConfigurationModel tm : dt.getTfModelList()) {
if (tm.getConfiguration_id() == configId) {
if (tm.isAnswer() == isAns) { // are values from both true
answer[i] = true;
} else {
answer[i] = false;
}
}
}
}
return answer;
}
Remember that short doesn't necessarily means better. Many times a longer method can be more readable and will be easier to understand and also maintain in the future. You will sometimes need to look at your code a year or 2 after you first wrote it and it ain't worth a thing if you can't understand it after you made it so short that you can't understand what you meant to do in that method. Of course that the other extreme is also something to be avoided and a too long method is not modular and can be difficult to understand if you want to change only a specific part of it.
In my opinion, that method you wrote is at a good length and doesn't need to be shortened.
But just to answer your question, you can always shorten your methods by dividing them to more methods. for example in your case:
public boolean[] validateTrueFalse(String[] checkBoxValues) {
boolean[] answer = new boolean[checkBoxValues.length];
for (int i = 0; i < checkBoxValues.length; i++) {
answer[i] = GetAnswer(checkBoxValues[i]);
}
return answer;
}
public bool GetAnswer(string aCheckBoxValue)
{
String[] values = aCheckBoxValue.split("_");
int configId = Integer.parseInt(values[0]);
boolean isAns = Boolean.parseBoolean(values[1]);
for (TrueFalseConfigurationModel tm : dt.getTfModelList())
{
if (tm.getConfiguration_id() == configId)
{
return tm.isAnswer() == isAns;
}
}
return false;
}
Notice how I divided the one big action in the method to smaller actions which created shorter methods. You can then continue in that manner and divide the GetAnswer method itself into 2 methods if you can find a logical way to divide it.
You can reduce
if (tm.isAnswer() == isAns) { // are values from both true
answer[i] = true;
} else {
answer[i] = false;
}
By
answer[i] = tm.isAnswer() == isAns;

Compare each string in datatable with that of list takes longer time.poor performance

I have a datatable of 200,000 rows and want to validate each row with that of list and return that string codesList..
It is taking very long time..I want to improve the performance.
for (int i = 0; i < dataTable.Rows.Count; i++)
{
bool isCodeValid = CheckIfValidCode(codevar, codesList,out CodesCount);
}
private bool CheckIfValidCode(string codevar, List<Codes> codesList, out int count)
{
List<Codes> tempcodes= codesList.Where(code => code.StdCode.Equals(codevar)).ToList();
if (tempcodes.Count == 0)
{
RetVal = false;
for (int i = 0; i < dataTable.Rows.Count; i++)
{
bool isCodeValid = CheckIfValidCode(codevar, codesList,out CodesCount);
}
}
}
private bool CheckIfValidCode(string codevar, List<Codes> codesList, out int count)
{
List<Codes> tempcodes= codesList.Where(code => code.StdCode.Equals(codevar)).ToList();
if (tempcodes.Count == 0)
{
RetVal = false;
}
else
{
RetVal=true;
}
return bRetVal;
}
codelist is a list which also contains 200000 records. Please suggest. I used findAll which takes same time and also used LINQ query which also takes same time.
A few optimizations come to mind:
You could start by removing the Tolist() altogether
replace the Count() with .Any(), which returns true if there are items in the result
It's probably also a lot faster when you replace the List with a HashSet<Codes> (this requires your Codes class to implement HashCode and Equals properly. Alternatively you could populate a HashSet<string> with the contents of Codes.StdCode
It looks like you're not using the out count at all. Removing it would make this method a lot faster. Computing a count requires you to check all codes.
You could also split the List into a Dictionary> which you populate with by taking the first character of the code. That would reduce the number of codes to check drastically, since you can exclude 95% of the codes by their first character.
Tell string.Equals to use a StringComparison of type Ordinal or OrdinalIgnoreCase to speed up the comparison.
It looks like you can stop processing a lot earlier as well, the use of .Any takes care of that in the second method. A similar construct can be used in the first, instead of using for and looping through each row, you could short-circuit after the first failure is found (unless this code is incomplete and you mark each row as invalid individually).
Something like:
private bool CheckIfValidCode(string codevar, List<Codes> codesList)
{
Hashset<string> codes = new Hashset(codesList.Select(c ==> code.StdCode));
return codes.Contains(codevar);
// or: return codes.Any(c => string.Equals(codevar, c, StringComparison.Ordinal);
}
If you're adamant about the count:
private bool CheckIfValidCode(string codevar, List<Codes> codesList, out int count)
{
Hashset<string> codes = new Hashset(codesList.Select(c ==> code.StdCode));
count = codes.Count(codevar);
// or: count = codes.Count(c => string.Equals(codevar, c, StringComparison.Ordinal);
return count > 0;
}
You can optimize further by creating the HashSet outside of the call and re-use the instance:
InCallingCode
{
...
Hashset<string> codes = new Hashset(codesList.Select(c ==> code.StdCode));
for (/*loop*/) {
bool isValid = CheckIfValidCode(codevar, codes, out int count)
}
....
}
private bool CheckIfValidCode(string codevar, List<Codes> codesList, out int count)
{
count = codes.Count(codevar);
// or: count = codes.Count(c => string.Equals(codevar, c, StringComparison.Ordinal);
return count > 0;
}

How to get out of repetitive if statements?

While looking though some code of the project I'm working on, I've come across a pretty hefty method which does
the following:
public string DataField(int id, string fieldName)
{
var data = _dataRepository.Find(id);
if (data != null)
{
if (data.A == null)
{
data.A = fieldName;
_dataRepository.InsertOrUpdate(data);
return "A";
}
if (data.B == null)
{
data.B = fieldName;
_dataRepository.InsertOrUpdate(data);
return "B";
}
// keep going data.C through data.Z doing the exact same code
}
}
Obviously having 26 if statements just to determine if a property is null and then to update that property and do a database call is
probably very naive in implementation. What would be a better way of doing this unit of work?
Thankfully C# is able to inspect and assign class members dynamically, so one option would be to create a map list and iterate over that.
public string DataField(int id, string fieldName)
{
var data = _dataRepository.Find(id);
List<string> props = new List<string>();
props.Add("A");
props.Add("B");
props.Add("C");
if (data != null)
{
Type t = typeof(data).GetType();
foreach (String entry in props) {
PropertyInfo pi = t.GetProperty(entry);
if (pi.GetValue(data) == null) {
pi.SetValue(data, fieldName);
_dataRepository.InsertOrUpdate(data);
return entry;
}
}
}
}
You could just loop through all the character from 'A' to 'Z'. It gets difficult because you want to access an attribute of your 'data' object with the corresponding name, but that should (as far as I know) be possible through the C# reflection functionality.
While you get rid of the consecutive if-statements this still won't make your code nice :P
there is a fancy linq solution for your problem using reflection:
but as it was said before: your datastructure is not very well thought through
public String DataField(int id, string fieldName)
{
var data = new { Z = "test", B="asd"};
Type p = data.GetType();
var value = (from System.Reflection.PropertyInfo fi
in p.GetProperties().OrderBy((fi) => fi.Name)
where fi.Name.Length == 1 && fi.GetValue(data, null) != null
select fi.Name).FirstOrDefault();
return value;
}
ta taaaaaaaaa
like that you get the property but the update is not yet done.
var data = _dataRepository.Find(id);
If possible, you should use another DataType without those 26 properties. That new DataType should have 1 property and the Find method should return an instance of that new DataType; then, you could get rid of the 26 if in a more natural way.
To return "A", "B" ... "Z", you could use this:
return (char)65; //In this example this si an "A"
And work with some transformation from data.Value to a number between 65 and 90 (A to Z).
Since you always set the lowest alphabet field first and return, you can use an additional field in your class that tracks the first available field. For example, this can be an integer lowest_alphabet_unset and you'd update it whenever you set data.{X}:
Init:
lowest_alphabet_unset = 0;
In DataField:
lowest_alphabet_unset ++;
switch (lowest_alphabet_unset) {
case 1:
/* A is free */
/* do something */
return 'A';
[...]
case 7:
/* A through F taken */
data.G = fieldName;
_dataRepository.InsertOrUpdate(data);
return 'G';
[...]
}
N.B. -- do not use, if data is object rather that structure.
what comes to my mind is that, if A-Z are all same type, then you could theoretically access memory directly to check for non null values.
start = &data;
for (i = 0; i < 26; i++){
if ((typeof_elem) *(start + sizeof(elem)*i) != null){
*(start + sizeof(elem)*i) = fieldName;
return (char) (65 + i);
}
}
not tested but to give an idea ;)

What does ExpressionVisitor.Visit<T> Do?

Before someone shouts out the answer, please read the question through.
What is the purpose of the method in .NET 4.0's ExpressionVisitor:
public static ReadOnlyCollection<T> Visit<T>(ReadOnlyCollection<T> nodes, Func<T, T> elementVisitor)
My first guess as to the purpose of this method was that it would visit each node in each tree specified by the nodes parameter and rewrite the tree using the result of the elementVisitor function.
This does not appear to be the case. Actually this method appears to do a little more than nothing, unless I'm missing something here, which I strongly suspect I am...
I tried to use this method in my code and when things didn't work out as expected, I reflectored the method and found:
public static ReadOnlyCollection<T> Visit<T>(ReadOnlyCollection<T> nodes, Func<T, T> elementVisitor)
{
T[] list = null;
int index = 0;
int count = nodes.Count;
while (index < count)
{
T objA = elementVisitor(nodes[index]);
if (list != null)
{
list[index] = objA;
}
else if (!object.ReferenceEquals(objA, nodes[index]))
{
list = new T[count];
for (int i = 0; i < index; i++)
{
list[i] = nodes[i];
}
list[index] = objA;
}
index++;
}
if (list == null)
{
return nodes;
}
return new TrueReadOnlyCollection<T>(list);
}
So where would someone actually go about using this method? What am I missing here?
Thanks.
It looks to me like a convenience method to apply an aribitrary transform function to an expression tree, and return the resulting transformed tree, or the original tree if there is no change.
I can't see how this is any different of a pattern that a standard expression visitor, other than except for using a visitor type, it uses a function.
As for usage:
Expression<Func<int, int, int>> addLambdaExpression= (a, b) => a + b;
// Change add to subtract
Func<Expression, Expression> changeToSubtract = e =>
{
if (e is BinaryExpression)
{
return Expression.Subtract((e as BinaryExpression).Left,
(e as BinaryExpression).Right);
}
else
{
return e;
}
};
var nodes = new Expression[] { addLambdaExpression.Body }.ToList().AsReadOnly();
var subtractExpression = ExpressionVisitor.Visit(nodes, changeToSubtract);
You don't explain how you expected it to behave and why therefore you think it does little more than nothing.

Resources