Click here to Skip to main content
15,896,063 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have an Array of strings. Each string contains multiple vars separated by a ",". I remember years ago when I did VB.NET there was a way to LINQ sort an array into corresponding vars, select which ones you need and use them however you like. For example:
Dim facultyQuery = From member In members
                          Let column = member.Split(","c)
                          Let name = column(0)
                          Let points = CInt(column(1))
                          Select name, points
                          Order By name

For Each member In facultyQuery
            strTemp = member.name
            Exit For
        Next

That was a simple LINQ sort for a drop down I made in VB. Now I'm looking to do the same in C#. My goal is to sort the data, take out what I don't need and put what I need into DataGridView control for display. Here's a sample of one of the strings:
C#
CAR_Sales_Default,2,0,2,0,00:24:56,00:00:00,0,69,-LWC_BG:#cc0000,-LCB_BG:#00cc00

I need to sort out the name, the 3rd number, the 2 times and their corresponding background and put that into a DataGridView. How can I do that using LINQ in C#?

Edit:
Got it working using something like this
C#
char[] splitChars = new char[] { ',' };

            var query = from data in tr
                        let columns = data.Split(splitChars, StringSplitOptions.None)
                        select new
                        {
                            qNames = columns[0].Substring(0, columns[0].Length - 6),
                            totCallW8 = Int32.Parse(columns[3]),
                            longW8InCall = columns[5],
                            longW8CallBack = columns[6],
                            BGtrLWC = columns[9].Substring(8),
                            BGtrLCB = columns[10].Substring(8),
                        }
                            into qSort
                            orderby qSort.qNames
                            select qSort;

            foreach (var result in query)
            {
                if (result.qNames.Contains(system))
                {
                    
                    dataGridView1.Rows.Add(result.qNames, result.totCallW8, result.longW8InCall, result.longW8CallBack);

                    dataGridView1.CurrentCell = dataGridView1.Rows[count].Cells[2];

                    dataGridView1[2, dataGridView1.CurrentRow.Index].Style.BackColor = ColorTranslator.FromHtml(result.BGtrLWC);
                    dataGridView1[3, dataGridView1.CurrentRow.Index].Style.BackColor = ColorTranslator.FromHtml(result.BGtrLCB);

                    count++;
                }
            }


What I have tried:

I could use a for loop and manually split them and add them to the GridView but that will take too long. My first approach to even displaying all the data in a ListView was a for loop and that made the run time very bad.
Posted
Updated 7-Feb-16 14:55pm
v2
Comments
BillWoodruff 6-Feb-16 10:19am    
If you want speed, you need to get the data into a form you can de-serialize into a List of Classes or Structs, and then do binding using that list.

If you want to use the same approach, this is how you could do it in C#:
C#
// this declaration as a class member:
static char[] splitChars = new char[] { ',' };

// just some sample data:
string[] rows = new string[] { "name2,1,2,3", "name1,3,4,5" };

var query = from row in rows
            let columns = row.Split(splitChars, StringSplitOptions.None)
            select new
            {
                name = columns[0],
                points = Int32.Parse(columns[1]),
            }
            into results
            orderby results.name
            select results;

foreach (var result in query)
{
    Console.WriteLine(String.Format("Name: {0}, Points: {1}", result.name, result.points));
}


But you might consider using a CSV reader instead. Here's an excellent one: A Fast CSV Reader[^]


Edit:
I missed the part that you want to display the result in a DataGridView. The fastest way to get there would be this:
C#
MydataGridView.DataSource = query.ToList();

However, if you want to modify the values in the DGV and then read them back into somewhere I would recommend using either a DataTable or a regular class for the results instead of the anonymous type constructed by the compiler in my sample above - so something like this instead:
C#
public class ResultRow
{
    public string Name { get; private set; } // non-editable in DGV
    public int Points { get; set; }          // editable in DGV

    public ResultRow(string name, int points)
    {
        Name = name;
        Points = points;
    }
}

// as a class member:
List<ResultRow> ResultsList;


var query2 = from row in rows
             let columns = row.Split(splitChars, StringSplitOptions.None)
             select new ResultRow(columns[0], Int32.Parse(columns[1])) into results
             orderby results.Name
             select results;

ResultsList = query2.ToList();

MyDataGridView.DataSource = ResultsList;


Edit 2 (after comment):
Sample code to add cell coloring based on values read from your source data - maybe not 100% what you want to achieve but I think you will get the idea:
C#
public partial class Form2 : Form
{
    static char[] splitChars = new char[] { ',' };

    BindingList<ResultRow> ResultsBindingList;

    public class ResultRow
    {
        public string Name { get; private set; } // non-editable in DGV
        public int Points { get; set; }          // editable in DGV
        public Color CellColor { get; private set; }

        public ResultRow(string name, int points, Color cellColor)
        {
            Name = name;
            Points = points;
            CellColor = cellColor;
        }
    }

    public Form2()
    {
        InitializeComponent();

        string[] rows = new string[] { "name2,1,2,3,#cc0000", "name1,3,4,5,#00cc00" };

        var query = from row in rows
            let columns = row.Split(splitChars, StringSplitOptions.None)
            let name = columns[0]
            let points = Int32.Parse(columns[1])
            let color = System.Drawing.ColorTranslator.FromHtml(columns[4])
            select new ResultRow(name, points, color) into results
            orderby results.Name
            select results;

        ResultsBindingList = new BindingList<ResultRow>(query.ToList());

        MyDataGridView.DataSource = ResultsBindingList;

        MyDataGridView.Columns["CellColor"].Visible = false;

        MyDataGridView.CellFormatting += MyDataGridViewCellFormatting;
    }

    private void MyDataGridViewCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    {
        e.CellStyle.BackColor = (Color)MyDataGridView["CellColor", e.RowIndex].Value;
    }

    private void AddRowButtonClick(object sender, EventArgs e)
    {
        ResultsBindingList.Add(new ResultRow("", 0, Color.Yellow));
    }
}
 
Share this answer
 
v6
Comments
[no name] 6-Feb-16 19:16pm    
Ok so that seemed to work. It was just me not understanding how the LINQ structure works in C#, thank you. Would you happen to know of a way to change the cells color when adding it?
In the foreach loop when adding the 2 time values I want to make their cells a specific color when adding the row. For some reason I only manage to change color of the last empty row
Sascha Lefèvre 6-Feb-16 19:56pm    
I've edited my answer above and put in some sample code for cell coloring - please take a look.

edit: wait.. there's a flaw in there - will edit
[no name] 6-Feb-16 20:02pm    
Is there no easier way than to call a method? I managed to get a solution going where when the new row gets added it calls a method and colors the cells based on a global var, but the 1st cell is always blank since the global var has not been set yet and after that all the rows are offset by 1. Is there really no inline color option when adding the row? For example how can I make something like this work better?
dataGridView1[2, count].Style.BackColor = ColorTranslator.FromHtml(result.BGtrLWC);
dataGridView1[3, count].Style.BackColor = ColorTranslator.FromHtml(result.BGtrLCB);

count++;
as right now it only colors the last row again.
Sascha Lefèvre 6-Feb-16 20:22pm    
I've edited my last sample code and added a method to add a row with cell coloring.

What do you mean by "inline color option"? Maybe you're not aware yet that the data that the DGV is bound to is in no way associated with any DGV styles - so you have to make that work yourself somehow; my sample code shows how to do it based on a Color value in a hidden column.
[no name] 6-Feb-16 20:32pm    
Ok that makes sense. Adding the color value to a hidden column and then instead of using a variable and passing it around actually reading the column value. So the column Color is kinda acting like a global var. Interesting! I'll give that a try. Right now I got it working by putting the color into an array and then using a for loop to go row by row adding the color.
Linq won't speed up the process that much - it's a loop as well, but it's a "deferred execution" loop that happens behind the scenes when the data is actually required instead of when the original query code is executed.

And if the run time is "very bad" when loading your data into any display control, that's normally a sign that you are trying to display far too much information. Never load a control with more than 100 rows, and preferably never with more than 20 or so - above that it's both slow and unusable for the user as he can't find what he needs to look at in the morass of the other data. Page it, filter it, but never just throw it all at the user!
 
Share this answer
 
Comments
[no name] 6-Feb-16 16:13pm    
I might've over exaggerated when I said bad. When I was using a for loop to display all the information it took 6 seconds but that's due to me making it read the source HTML page with xpath and record what it finds each time. I have since changed it to save ChildNodes into the array and display that which takes 0.5 sec.
The whole point of this project is to make the 300+ entry table smaller. It has some junk I don't need and so I only want to display certain information from it. Maybe multiple DGV with different information, so I'm scanning, sorting and displaying into multiple smaller pieces.
BillWoodruff 8-Feb-16 0:28am    
+5 absurd down-vote countered

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900