Optimize code block for LINQ and non LINQ

Posted on

Problem

I have 2 code block to do same a work and have same target create some thing, but I don’t know which block is the best (I mean LINQ or non-LINQ)?

First of all, can anyone tell me how to optimize on the code blocks? And the lastly, help me find the best style between LINQ and non-LINQ:

First block is:

if (tblone.Rows.Count > 0)
        {
            tblone.Rows.Cast<DataRow>().Where(x => (string)x["id"] == "true").ToList()
                .ForEach(x => tbltwo.Rows.Cast<DataRow>().Where(y => y["category"] == x["cate"]).ToList().ForEach(
                    z =>
                    {
                        tblthree.Rows.Cast<DataRow>()
                                          .ToList<DataRow>()
                                          .ForEach(k => datatemp.Rows.Add(k["m"].ToString()));
                        tblfour.Rows.Cast<DataRow>()
                            .ToList<DataRow>()
                            .ForEach(k => datatemp.Rows.Add(k["m"].ToString()));
                    }));
        }

Second block is:

if (tblone.Rows.Count > 0)
        {
            for (var idx = 0; idx < tblone.Rows.Count; idx++)
            {
                if (bool.Parse(tblone.Rows[idx]["subset"].ToString()))
                {
                    for (var kdx = 0; kdx < tbltwo.Rows.Count; kdx++)
                    {
                        if (tbltwo.Rows[kdx]["category"].ToString() == tblone.Rows[idx]["cate"].ToString())
                        {
                            for (var zdx = 0; zdx < tblthree.Rows.Count; zdx++)
                                datatemp.Rows.Add(tblthree.Rows[zdx]["m"].ToString());
                            for (var zdx = 0; zdx < tblfour.Rows.Count; zdx++)
                                datatemp.Rows.Add(tblfour.Rows[zdx]["m"].ToString());
                        }
                    }
                }
            }
        }

Solution

First – if you are working with DataTables, then you can use Linq to DataSet, which has nice extension methods to get field values.

Now let’s review logic of your code. You are not using any data from tblone and tbltwo in your result. Actually you only finding joined categories between these two tables, and for each matched rows pair you are adding all m values from tblthree and tblfour to result. I find this logic pretty strange. Maybe you are expecting only single match here. Then you will need boolean result (match found or not). But basically you need count of joined rows:

var matchedCategoriesCount = 
            (from one in tblone.AsEnumerable().Where(r => r.Field<bool>("id"))
             join two in tbltwo.AsEnumerable()
                on one.Field<string>("cate") equals two.Field<string>("category")
             select one).Count();

Same with lambda syntax if you find it more readable:

var matchedCategoriesCount = 
            tblone.AsEnumerable().Where(r => r.Field<bool>("id"))
                  .Join(tbltwo.AsEnumerable(),
                        one => one.Field<string>("cate"),
                        two => two.Field<string>("category"),
                        (one, two) => one)
                  .Count();

Then you can select m values from tblthree and tblfour N times and create new DataTable:

// if (matchedCategoriesCount > 0)
var values = tblthree.AsEnumerable().Concat(tblfour.AsEnumerable())
                     .Select(r => r.Field<string>("m")))
                     .ToArray();

You can even use simple loop here:

for(int i = 0; i < matchedCategoriesCount; i++)
   foreach(var value in values)
       datatemp.Rows.Add(value);

And last – don’t use variable names like tblone, tbltwo, tblthree etc. These names does not explain what data these variables hold. Use names from domain of your application.

Leave a Reply

Your email address will not be published. Required fields are marked *