Reputation: 804
Example input and current output with out sorting:
List<List<string>> _optoGrid = new List<List<string>>();
_optoGrid.Add(new List<string>() {"10", "10", "100", "20", "10", "10"});
_optoGrid.Add(new List<string>() {"20", "20", "50", "10", "1546", "555"});
_optoGrid.Add(new List<string>() {"30", "30", "10", "10", "10", "100"});
_optoGrid.Add(new List<string>() {"30", "30", "10", "1", "10", "100"});
display this is where the sort code would go.
foreach (List<string> list in _optoGrid)
{
foreach (string s in list)
{
Console.Write(s + ", ");
}
Console.WriteLine();
}
Current Output:
10, 10, 100, 20, 10, 10,
20, 20, 50, 10, 1546, 555,
30, 30, 10, 10, 10, 100,
30, 30, 10, 1, 10, 100,
Desired Output assuming sort by column 5 (starting at 0):
20, 20, 50, 10, 1546, 555,
30, 30, 10, 10, 10, 100,
30, 30, 10, 1, 10, 100,
10, 10, 100, 20, 10, 10,
in my head I would like to type:
_optogrid.Sort(5) //5 being the 'column' number
Upvotes: 0
Views: 971
Reputation: 30464
This looks like sorting a table by a certain column number.
Enumerable.OrderBy
will do the job.
Enumerable.OrderBy, that takes a sequence of TRow
items, and a keySelector. A keySelector is a function that takes a TRow
as input and returns a value on which the sequence must be ordered.
In your case, a TRow
is a List<string>
. So if you need to order by the column with index sortColumnIndex
you need a KeySelector that takes a List<String> row
and returns row[sortColumnIndex]
How about this:
int sortColumnIndex = 5; // order by column 5 List> unorderedList = ... List orderedList = unorderedList.OrderBy(row => row[sortColumnIndex]);
Simple comme bonjour!
Upvotes: 0
Reputation: 131364
This code has no columns, it's a list that contains lists. LINQ can still order the results. The methods that order results in LINQ are OrderBy()
and OrderByDescending()
. Its argument is a lambda that produces the ordering key.
In this case, the lambda should return the list item that should be used for ordering, eg :
var _optoGrid = new List<List<string>>{
new List<string> {"10", "10", "100", "20", "10", "10"},
new List<string> {"20", "20", "50", "10", "1546", "555"},
new List<string> {"30", "30", "10", "10", "10", "100"},
new List<string> {"30", "30", "10", "1", "10", "100"}
};
var orderedResults=_optoGrid.OrderBy(lst=>lst[5]);
Or
var orderedResults=_optoGrid.OrderByDescending(lst=>lst[5]);
That's very fragile code though. Nothing guarantees that all lists have the same number of items. It's very easy to forget one value or enter one more. .OrderBy(lst=>lst[5])
will throw if one list contains fewer than 6 items but won't complain if the wrong number of items are used.
It would be better if a proper class was used instead of lists, especially if all items are expected to have the same number of items, eg :
class MyItem
{
public string ProperlyNamedProperty1{get;set;}
...
public MyItem(string prop1,string prop2,...)
{
ProperlyNamedProperty1=prop1;
...
}
}
var _optoGrid = new List<MyItem>{
new MyItem("10", "10", "100", "20", "10", "10"),
};
var orderedResults=_optoGrid.OrderBy(item=>item.Property6);
Value tuples can also be used if the list is only going to be used locally, eg in a single method. Of course, 6 properties are a bit too much :
var _optoGrid = new List<(string prop1, string prop2, string prop3, string prop4, string prop5, string prop6)>{
("10", "10", "100", "20", "10", "10"),
("20", "20", "50", "10", "1546", "555"),
("30", "30", "10", "10", "10", "100"),
("30", "30", "10", "1", "10", "100")
};
var orderedResults=_optoGrid.OrderBy(tuple=>tuple.prop6);
If one is feeling very lazy and the number of items isn't that greate, the names can be ommited:
var _optoGrid = new List<(string, string, string, string, string, string)>{
("10", "10", "100", "20", "10", "10"),
("20", "20", "50", "10", "1546", "555"),
("30", "30", "10", "10", "10", "100"),
("30", "30", "10", "1", "10", "100")
};
var orderedResults=_optoGrid.OrderBy(tuple=>tuple.Item6);
The nice thing about tuples is they are strongly typed. There's no reason to use the same type for all of them, eg :
var _optoGrid = new List<(int, int, string, string, string, double)>{
(10, 10, "100", "20", "10", 10),
(20, 20, "50", "10", "1546", 555),
(30, 30, "10", "10", "10", 100),
(30, 30, "10", "1", "10", 100)
};
var orderedResults=_optoGrid.OrderBy(tuple=>tuple.Item6);
This avoids another thorny issue, that of lexicographical ordering. If I change a string from "10"
to "1000" it will *still* appear before "555", because words that start with
"1"always come before words that start with
"5". Using strings, OrderBy
will return :
10 10 100 20 10 10000
20 20 50 10 1546 555
Ooops.
Using an int
or double
for the sixth field though, we get the expected order :
20 20 50 10 1546 555
10 10 100 20 10 10000
Upvotes: 4