Link to home
Start Free TrialLog in
Avatar of Gani tpt
Gani tpt

asked on

How to write LINQ query to split and find the column min and maximum and return based on string values.

Hi,

How to write LINQ query to split and find the column min and maximum and return based on string values.

I done some code using LINQ, but it is not working.

what is the problem in my code.

Scenario is,

1. Split the string and find the column

2. Check the minimum and maximum range of each splitted string. (SUB C=100#SUB D=200)

3 range should check within the limit like 100 min and max

Hi,

How to write LINQ query to split and find the column min and maximum and return based on string values.

I done some code using LINQ, but it is not working.

what is the problem in my code.



 protected void Button_Click(object sender, EventArgs e)
    {

        
        string string1 = "SUB C=100#SUB D=200";

        string FinalOutput = "GRADE#SUB B";

        DataTable dt = new DataTable();
        dt.Columns.AddRange(new[] { new DataColumn("Studentno"),new DataColumn("GRADE"),new DataColumn("SUB B"), new DataColumn("SUB C(MIN)"), new DataColumn("SUB C(MAX)"),
new DataColumn("SUB D(MIN)") ,new DataColumn("SUB D(MAX)") ,new DataColumn("SUB C"),new DataColumn("FROM"),new DataColumn("TO") });
        dt.Rows.Add(101,"A", "100", "100", "200", "200", "300", null, 20, "100");
        dt.Rows.Add(101, "B", "100", "150", "250", "250", "350", null, 20, "100");
        dt.Rows.Add(101, "B", "100", "200", "300", "100", null, null, 20, "100");
        dt.Rows.Add(101, null, "100", "200", "300", "100", null, null, 20, "100");



        //Check whether a given column name exists or not


        string[] word1 = string1;

        List<string> FinalResult = new List<string>

        for (int i = 0; i < word1.Length; i++)
        {

          string ChkMark = word1[i];

            var results = (from row in dt.AsEnumerable()
                           from pair in
                               (from term in ChkMark.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                let pair = term.Split(new[] { '=' })
                                where pair.Count() == 2 && int.TryParse(pair[1], out dimens)
                                select new KeyValuePair<string, int>(pair[0], dimens))
                           where row[pair.Key + "(MIN)"] != DBNull.Value && row[pair.Key + "(MAX)"] != DBNull.Value
                           let r1 = Convert.ToInt64(row[pair.Key + "(MIN)"])
                           let r2 = Convert.ToInt64(row[pair.Key + "(MAX)"])
                           let FrSize = Convert.ToDouble(row.Field<double>("FROM"))
                           let ToSize = Convert.ToDouble(row.Field<double>("TO"))
                           where pair.Value >= r1 && pair.Value <= r2 &&
                         
                           AvgMarks >= FrSize && AvgMarks <= ToSize
                           select new
                           {

                                FinalValue = row[column] // Need to get column value of FinalOutput. Output is GRADE=A and SUB B=100

                           }).Distinct();


            FinalResult.Add(word1[i] + "=" + FinalValue);

        }

        //finally Result





    }

Open in new window




My final output should return in in the List.
[0] GRADE=A
[1] SUB B=100

what is the problem in my code...
Avatar of Gani tpt
Gani tpt

ASKER

Any queries......pls. let me know...This is important to us and need asap...........pls..
Avatar of Fernando Soto
Can you explain in words what is needed to do what you need, I am having trouble following your query. Thanks.
done.thanks...
What is done?
Sorry for the late response. Actually we tried to change the logic. but, it is not working.

I will explain step by step.

 DataTable dt = new DataTable();
        dt.Columns.AddRange(new[] { new DataColumn("Studentno"),new DataColumn("GRADE"),new DataColumn("SUB B"), new DataColumn("SUB C(MIN)"), new DataColumn("SUB C(MAX)"),
new DataColumn("SUB D(MIN)") ,new DataColumn("SUB D(MAX)") ,new DataColumn("SUB C"),new DataColumn("FROM"),new DataColumn("TO") });
        dt.Rows.Add(101,"A", "100", "100", "50", "200", "250", "700", 20, "100");
        dt.Rows.Add(101, "B", "100", "150", "70", "250", "200", "100", 20, "100");
        dt.Rows.Add(101, "B", "100", "200", "300", "100", "250", null, 20, "100");
        dt.Rows.Add(101, null, "100", "200", "300", "100", "200", null, 20, "100");

1. I have two input strings.
    1-  string1 = "GRADE#SUB B";
    2-  string string2 = "SUB C=100#SUB D=300";

2. I have the following conditions.
    First i want to get the row which contains in the range between within 100 ((i.e) SUB C (MIN) and SUB C (MAX)) (take string2 and split the string and take first in that. SUB C=100).

   so i may get below two records. (for condition SUB C=100)
 
           dt.Rows.Add(101,"A", "100", "100", "50", "200", "250", "700", 20, "100");
           dt.Rows.Add(101, "B", "100", "150", "70", "250", "200", "100", 20, "100");

3. After that, with in the above two records, i want to filter one more condition need to check. (i.e : for SUB D=300
    This is also need to check within Min and Max of SUB D=300.

    So finally ia may get only one records.

          dt.Rows.Add(101,"A", "100", "100", "50", "200", "250", "700", 20, "100");

4. In that, finally i want to get the records for the field of ( GRADE and SUB B).

So the final output would be

GRADE=A
SUB B=100.

Note : Filter and check row within the row using string2 and display the result in the form of string1.

pls. let us know if you need any more details.

The output i want either simple C# or Linq Query..???
Hi Ganesh;

I have one more issue to understand and that is this from your last post, "3. After that, with in the above two records, i want to filter one more condition need to check. (i.e : for SUB D=300", but 300 falls outside of the range of SUB D(MIN) and SUB D(MAX) for both records but you selected, "dt.Rows.Add(101,"A", "100", "100", "50", "200", "250", "700", 20, "100");", How?

This code selects the two records and per the instructions but step 3 still needs to be implemented.
DataTable dt = new DataTable();
dt.Columns.AddRange(new[] { new DataColumn("Studentno"),new DataColumn("GRADE"),new DataColumn("SUB B"), new DataColumn("SUB C(MIN)"), new DataColumn("SUB C(MAX)"),
new DataColumn("SUB D(MIN)") ,new DataColumn("SUB D(MAX)") ,new DataColumn("SUB C"),new DataColumn("FROM"),new DataColumn("TO") });
dt.Rows.Add(101, "A", "100", "100", "50", "200", "250", "700", 20, "100");
dt.Rows.Add(101, "B", "100", "150", "70", "250", "200", "100", 20, "100");
dt.Rows.Add(101, "B", "100", "200", "300", "100", "250", null, 20, "100");
dt.Rows.Add(101, null, "100", "200", "300", "100", "200", null, 20, "100");

string string1 = "GRADE#SUB B";
string string2 = "SUB C=100#SUB D=300";
string[][] subCD = string2.Split('#').Select(s => s.Split('=') ).ToArray();

var result = from row in dt.AsEnumerable()
			 let min = (Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MIN)")) <= Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MAX)"))) ? Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MIN)")) : Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MAX)"))
			 let max = (Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MIN)")) >= Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MAX)"))) ? Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MIN)")) : Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MAX)"))
			 let val = Convert.ToInt32(subCD[0][1])
			 where min <= val && max >= val
			 select row;

Open in new window

Sorry. pls. see the below corrected datatable sample records.

  DataTable dt = new DataTable();
        dt.Columns.AddRange(new[] { new DataColumn("Studentno"),new DataColumn("GRADE"),new DataColumn("SUB B"), new DataColumn("SUB C(MIN)"), new DataColumn("SUB C(MAX)"),
new DataColumn("SUB D(MIN)") ,new DataColumn("SUB D(MAX)") ,new DataColumn("SUB C"),new DataColumn("FROM"),new DataColumn("TO") });
        dt.Rows.Add(101, "A", "100", "80", "200", "200", "500", "700", 20, "100");
        dt.Rows.Add(101, "B", "100", "70", "250", "250", "200", "100", 20, "100");
        dt.Rows.Add(101, "B", "100", "200", "300", "100", "250", null, 20, "100");
        dt.Rows.Add(101, null, "100", "200", "300", "100", "200", null, 20, "100");

Also, minimum condition >= and maximum condition <= should apply. i have changed your query. but, it returns 0(zero) count.

see the below code:

    protected void Button8_Click(object sender, EventArgs e)
    {

        DataTable dt = new DataTable();
        dt.Columns.AddRange(new[] { new DataColumn("Studentno"),new DataColumn("GRADE"),new DataColumn("SUB B"), new DataColumn("SUB C(MIN)"), new DataColumn("SUB C(MAX)"),
new DataColumn("SUB D(MIN)") ,new DataColumn("SUB D(MAX)") ,new DataColumn("SUB C"),new DataColumn("FROM"),new DataColumn("TO") });
        dt.Rows.Add(101, "A", "100", "80", "200", "200", "500", "700", 20, "100");
        dt.Rows.Add(101, "B", "100", "70", "250", "250", "200", "100", 20, "100");
        dt.Rows.Add(101, "B", "100", "200", "300", "100", "250", null, 20, "100");
        dt.Rows.Add(101, null, "100", "200", "300", "100", "200", null, 20, "100");

        string string1 = "GRADE#SUB B";
        string string2 = "SUB C=100#SUB D=300";
        string[][] subCD = string2.Split('#').Select(s => s.Split('=')).ToArray();

        var result = from row in dt.AsEnumerable()
                     let min = (Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MIN)")) >= Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MAX)"))) ? Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MIN)")) : Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MAX)"))
                     let max = (Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MIN)")) <= Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MAX)"))) ? Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MIN)")) : Convert.ToInt32(row.Field<string>(subCD[0][0] + "(MAX)"))
                     let val = Convert.ToInt32(subCD[0][1])
                     where min >= val && max <= val
                     select row;

       
    }

it returns 0(zero) count.

But, it returns on record.

1. for the first filter two records, (For : SUB C=100)
 i.e :   dt.Rows.Add(101, "A", "100", "80", "200", "200", "500", "700", 20, "100");
        dt.Rows.Add(101, "B", "100", "70", "250", "250", "200", "100", 20, "100");

2. second filter one records  (For :SUB D=300)
  dt.Rows.Add(101, "A", "100", "80", "200", "200", "500", "700", 20, "100");

So, the GRADE : A and SUB B : 100.

Note : string2 is not a static values. it is dynamic and It may be the values three or four etc.. Ex ("SUB C=100#SUB D=300#SUB E=150#SUB G=320"....

Where we need to change the Query...?
any update pls..
ASKER CERTIFIED SOLUTION
Avatar of Fernando Soto
Fernando Soto
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for your solution.

What happened if more than two paramteres like (  SUB C=100#SUB D=300#SUB E=400#SUB F=200...etc ).

Because this is not static. string2 is dynamic. it will come two or three or four etc.

In that case how to handle in the LINQ Code...

can you give some more alternative solution for this..

because we are trying some alternative solution for a long time...

this scenario is little bit tricky and finding the exact solution...
To your statement, "What happened if more than two paramteres like (  SUB C=100#SUB D=300#SUB E=400#SUB F=200...etc ).".
How would you handle the other parameters like the previous solution where you are looking for values between C(MIN) and C(MAX) as well as for the others?

Is it like the other where both C and D had to be true in other words C && D or C && D && E && F?

In your DataTable I do not see any columns for Sub E(MIN), Sub E(MAX), Sub F(MIN), Sub F(MAX) and etc.... Are the number of columns dynamic?

What else has not been stated?
I have given the sample only.

definitely, if datatable column is there then the parameter also be there.

if there is no matching column in datatable then it should check remaining parameter and matching column and then finally get the count.

So, our case need to form for the dynamic parameter.

i have given sample datatable for 3 parameters..if it 4 parameter then the column not found, we need to get the result count for remaining parameter.

Note : Anyhow, column always there based on the parameter...

see below sample code i have added SUB E(Min) and SUB E(Max).

        string string2 = "SUB C=100#SUB D=250#SUB E=300";

 DataTable dt = new DataTable();
        dt.Columns.AddRange(new[] { new DataColumn("Studentno"),new DataColumn("GRADE"),new DataColumn("SUB B"), new DataColumn("SUB C(MIN)"), new DataColumn("SUB C(MAX)"),
        new DataColumn("SUB D(MIN)") ,new DataColumn("SUB D(MAX)"), new DataColumn("FROM"),new DataColumn("TO"),new DataColumn("SUB E(MIN)"), new DataColumn("SUB E(MAX)") });
        dt.Rows.Add(101, "A", "100", "80", "200", "200", "550", 20, "100", "200", "500");
        dt.Rows.Add(101, "B", "100", "90", "300", "270", "200", 20, "100", null, null);
        dt.Rows.Add(101, "B", "100", "200", "300", "100", "250", 20, "100", "100", "100");
        dt.Rows.Add(101, null, "100", "200", "300", "100", "200", 20, "100", null, null);
        DataView dataView = dt.DefaultView;


if SUB G=400, then definitely this column will be there in the datatable.

Is it like the other where both C and D had to be true in other words C && D or C && D && E && F?

Ans : The row filter shoud check one by one parameter and then finally get one single row only always..

pls. let us know whether you can undarestand or not the scenario...
updated and corrected datatable...

DataTable dt = new DataTable();
        dt.Columns.AddRange(new[] { new DataColumn("Studentno"),new DataColumn("GRADE"),new DataColumn("SUB B"), new DataColumn("SUB C(MIN)"), new DataColumn("SUB C(MAX)"),
        new DataColumn("SUB D(MIN)") ,new DataColumn("SUB D(MAX)"), new DataColumn("FROM"),new DataColumn("TO"),new DataColumn("SUB E(MIN)"), new DataColumn("SUB E(MAX)") });
        dt.Rows.Add(101, "A", "100", "80", "200", "200", "550", 20, "100", "200", "500");
        dt.Rows.Add(101, "B", "100", "90", "300", "270", "200", 20, "100", null, null);
        dt.Rows.Add(101, "B", "100", "200", "300", "100", "250", 20, "100", "100", "100");
        dt.Rows.Add(101, null, "100", "200", "300", "100", "200", 20, "100", null, null);
        DataView dataView = dt.DefaultView;
Hi Ganesh;

Standard Linq queries are static in nature. So when you create your filtering, where clause, for example you give a variable can compare it to some value. So if your where clause has one object to  compare with one value you can not add at run time more or less objects and values to to compare to and filter on, that would make it a dynamic query. There are some NuGet packages that can build dynamic queries at run time and one such package is "Dynamic Linq Query Builder". That package has a ASP .Net sample application to show how it works and how to build the dynamic queries. With that and my sample I posted above you can build the queries you need.
Thanks Fernando.  i tried some other way to form the login and doing the code. 

it's working. but, the last condition showing error - column not found A1 ==> actually A1 is not a column. it is a value.

see my complete code.

Thanks. i tried to add two more condition.

pls. confirm the way of condition of correct or not..

finally i am getting error - column not found A1 ==> A1 is is a column it is a value.

see my complete code.

 DataTable dt = new DataTable();
         dt.Columns.AddRange(new[] { new DataColumn("Studentno",typeof(int)),new DataColumn("GRADE"),new DataColumn("SUB B",typeof(int)), 
         new DataColumn("SUB C(MIN)",typeof(int)), new DataColumn("SUB C(MAX)",typeof(int)),new DataColumn("SUB D(MIN)",typeof(int)) ,
         new DataColumn("SUB D(MAX)",typeof(int)), new DataColumn("FROM"),new DataColumn("TO"),new DataColumn("SUB E(MIN)",typeof(int)), 
         new DataColumn("SUB E(MAX)",typeof(int)),new DataColumn("Dept",typeof(string)) });
         dt.Rows.Add(101, "A", 100, 80, 200, 200, 550, 20, 100, 200, 500,"A1");
         dt.Rows.Add(101, "B", 100, 90, 300, 270, 200, 20, 100, null, null,"B1");
         dt.Rows.Add(101, "B", 100, 200, 300, 100, 250, 20, 100, 100, 100,"C1");
         dt.Rows.Add(101, null, 100, 200, 300, 100, 200, 20, 100, null, null,"D1");


        List<string> AllColumns1 = new List<string>() { "GRADE", "SUB B" };

        string[] AllColumns = AllColumns1.ToArray();
        string string2 = "SUB C=100#SUB D=250#SUB E=300";

        string[] paras = string2.Split('#');
        List<DataRow> list = new List<DataRow>();
        string sqlcmd = "";

        for (int i = 0; i < paras.Length; i++)
        {
            string[] par = paras[i].Split('=');
            string mixpar = par[0] + "(MIN)";
            string maxpar = par[0] + "(MAX)";
            int mvalue = Convert.ToInt32(par[1]);
            sqlcmd += " ( [" + mixpar + "] <  " + mvalue + "  and  [" + maxpar + "] >  " + mvalue + " ) ";
            if ((i + 1) != paras.Length)
            {
                sqlcmd += " and ";
            }


        }

        // For From and To comparison
        string FrS = "From";
        string ToS = "To";
        double msize = 20;
        sqlcmd += " and ( [" + FrS + "] <  " + msize + "  and  [" + ToS + "] >  " + msize + " ) ";

        // For dept
        string strdeptvalue = "A1";
        string strdept = "Dept";
        sqlcmd += " and ( [" + strdept + "] = " + strdeptvalue + ") ";

        DataRow[] result = dt.Select(sqlcmd);
         List<string> result1 = new List<string>();
           
            for (int i = 0; i < AllColumns.Length; i++) 
            {

                foreach (DataRow row in result)
                {
                    result1.Add(AllColumns[i] + "=" + row[AllColumns[i]]);
                }
               

            }

what is the problem...

Open in new window

Yes. i debugg and found the solution.

we need to enclose '(single quotes) before and after of A1.

Thanks buddy...

It's working now..

Note : If you have any alternate solution pls. provide us. we will keep in mind...
No that looks good to me.
Solution posted