Binding multiple values to different variables in c# using for loop - c#

How should i bind the values without using index no. as above, how can use forLoop here if possible. in query i gor 14 rows and 4 columns.
public class SLRInvestmentPrev
{
[DbCol("BOOK_VALUE")]
public double BOOK_VALUE { get; set; }
[DbCol("INSTRUMENT_ID")]
public int instrument_id { get; set; }
}
Public void Compute()
{
var slrinvestmentPrev = Database.BindList<SLRInvestmentPrev>(Transaction, #"Query here");
View["BOOK_VALUE_HTM0"] = slrinvestmentPrev[0].BOOK_VALUE;
View["BOOK_VALUE_HTM1"] = slrinvestmentPrev[1].BOOK_VALUE;
View["BOOK_VALUE_HTM2"] = slrinvestmentPrev[2].BOOK_VALUE;
View["BOOK_VALUE_HTM3"] = slrinvestmentPrev[3].BOOK_VALUE;
View["BOOK_VALUE_HFT1"] = slrinvestmentPrev[4].BOOK_VALUE;
View["BOOK_VALUE_HFT2"] = slrinvestmentPrev[5].BOOK_VALUE;
View["BOOK_VALUE_HFT3"] = slrinvestmentPrev[6].BOOK_VALUE;
View["BOOK_VALUE_HFT4"] = slrinvestmentPrev[7].BOOK_VALUE;
View["BOOK_VALUE_HFT5"] = slrinvestmentPrev[8].BOOK_VALUE;
View["BOOK_VALUE_AFS1"] = slrinvestmentPrev[9].BOOK_VALUE;
View["BOOK_VALUE_AFS2"] = slrinvestmentPrev[10].BOOK_VALUE;
View["BOOK_VALUE_AFS3"] = slrinvestmentPrev[11].BOOK_VALUE;
View["BOOK_VALUE_AFS4"] = slrinvestmentPrev[12].BOOK_VALUE;
View["BOOK_VALUE_AFS5"] = slrinvestmentPrev[13].BOOK_VALUE;
}

given your books are HTM0 to AFS5 you could do something like
List<String> booklist = new List<string>(new String[] { "BOOK_VALUE_HTM0", "BOOK_VALUE_HTM1", "BOOK_VALUE_HTM2",<.....> "BOOK_VALUE_AFS5" } ); // or populate from some other means
int index = 0;
foreach (String sbook in booklist)
{
View[sbook] = slrinvestmentPrev[index].BOOK_VALUE;
index++
}

how to bind that right side index values to different variables using
for loop or is there any way to make code short and being error free
if suppose to be rows no are less than hard coded index values?
So you need a way to bind your names to the indexes, one way it to use a Dictionary:
var nameIndexes = new Dictionary<int, string>()
{
{ 0, "BOOK_VALUE_HTM0" }, { 1, "BOOK_VALUE_HTM1" }, { 2, "BOOK_VALUE_HTM2" }, { 3, "BOOK_VALUE_HTM3" },
{ 4, "BOOK_VALUE_HFT1" }, { 5, "BOOK_VALUE_HFT2" }, { 6, "BOOK_VALUE_HFT3" }, { 7, "BOOK_VALUE_HFT4" }, { 8, "BOOK_VALUE_HFT5" },
{ 9, "BOOK_VALUE_AFS1" }, { 10, "BOOK_VALUE_AFS2" }, { 11, "BOOK_VALUE_AFS3" }, { 12, "BOOK_VALUE_AFS4" }, { 13, "BOOK_VALUE_AFS5" }
};
for(int i = 0; i < slrinvestmentPrev.Count; i++)
{
View[nameIndexes[i]] = slrinvestmentPrev[i].BOOK_VALUE;
}
If the index always starts with 0 and has no gaps you could also use a List<string> or string[].

Related

Use a multidimensional array of strings to write to file

I'm trying to develop a simple EPOS system that records inventory and processes transactions. At the moment I want it to write the contents of my arrays (Product, Price, Size, Stock Level) to file using Streamwriter as well as a random date at the top but I haven't been able to crack it. My global variables declared for these arrays are below.
readonly static string[] Products = { "1989 Jersey", "1977 Jersey", "2001 Jersey", "1986 Jersey", "1990 Jersey", "2005 Jersey", "1992 Jersey", "1996 Jersey", "1985 Jersey", "1989 Jersey", "1991 Jersey", "1992 Jersey", "1986 Jersey"};
readonly static decimal[] Price = {26m, 24m, 21m, 25m, 19m, 22m, 23m, 18m, 16.50m, 17.50m, 14m, 20m, 17.50m};
readonly static string[] Sizes = {"Extra Small", "Small", "Medium", "Large", "Extra Large"};
readonly static int[,] StartingStock = {{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 }};
I am currently trying to get my code to work. I am invoking the method above in a Form Load event and it only passes the contents at Index 0,0 to file.
private void WriteToFileOpeningStock()
{
string[] Productlist = { Products[0], Sizes[0] };
try
{
//enable StreamwWriter Object
StreamWriter outputfile;
// create file
outputfile = File.CreateText("ProductList.txt");
//writing array contents to file
for (int index = 0; index < Productlist.Length; index++)
{
outputfile.WriteLine(Productlist[index]);
outputfile.WriteLine("");
}
outputfile.Close();
MessageBox.Show("Data Entered");
}
catch
{
MessageBox.Show("Error");
}
I tried to write string[] Productlist = { Products[0-12], Sizes[0-4] }; to get it to pass all of the array contents but it throws an exception "Index was outside the bounds of the array". I am new to C# and programming so any help would be very much appreciated.
You are looping through ProductList:
string[] Productlist = { Products[0], Sizes[0] };
This only has the first index of the Product inside and the first index of Sizes inside. So there are only two values it will output.
You need to create two nested for loops, looping through both Products and Sizes
If you just looking to list the products you could do something like this
try
{
//enable StreamwWriter Object
StreamWriter outputfile;
// create file
outputfile = File.CreateText("ProductList.txt");
//writing array contents to file
for (int index = 0; index < Products.Length; index++)
{
outputfile.WriteLine(Products[index]);
outputfile.WriteLine("");
}
outputfile.Close();
MessageBox.Show("Data Entered");
}
catch
{
MessageBox.Show("Error");
}
In general I would Create a Class to hold your product. Something like
public class Product
{
public string ProductName { get; set; }
public List<string> Sizes { get; set; }
public decimal Price { get; set; }
}
then you can do something like this to convert to the new class
Productlist = new List<Product>();
for (int x = 0; x < Products.Length; x++)
{
Productlist.Add(new Product()
{
ProductName = Products[x],
Price = Price[x],
Sizes = Sizes.ToList()
});
}
WriteToFileOpeningStock();
Then you could make the following changes to list the products in a file
private void WriteToFileOpeningStock()
{
try
{
//enable StreamwWriter Object
StreamWriter outputfile;
// create file
outputfile = File.CreateText("ProductList.txt");
//writing array contents to file
foreach(Product product in Productlist)
{
outputfile.WriteLine(product.ProductName);
outputfile.WriteLine("");
}
outputfile.Close();
MessageBox.Show("Data Entered");
}
catch
{
MessageBox.Show("Error");
}
}

converting int to List<double?>, ChartJS Core

I'm working on a web application. I found this interesting https://github.com/mattosaurus/ChartJSCore. to use charts in my application.
The charts are working successfully in most pages. But in one page i have the following idea:
I have 3 properties (Appropriate, Inappropriate, NoInteraction) in my model all with type (int) and i need to keep it as integer to manipulate other functionalities in the application. Each property will be represented as one series in the chart and it should be list or array of 15 integer always.
Here is my properties in Session Model:
public int DayNumber { get; set; }
public int Appropriate { get; set; }
public int NotAppropriate { get; set; }
public int NoInteraction { get; set; }
Here is my Controller:
public IActionResult Details()
{
var result = _db.Session.ToList();
//I want this appropriateLine to be passed to GenerateLineChart method but whenever i tried i came up with an error of converting types.
var AppropriateLine = result.Select(x => x.Appropriate).ToList();
Chart lineChart = GenerateLineChart();
ViewData["LineChart"] = lineChart;
return View();
}
private static Chart GenerateLineChart()
{
Chart chart = new Chart();
chart.Type = Enums.ChartType.Line;
ChartJSCore.Models.Data data = new ChartJSCore.Models.Data();
data.Labels = new List<string>() { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" };
LineDataset AppropriateDataset = new LineDataset()
{
Label = "Appropriate Data Line",
Data = new List<double?>() { 2, 6, 2, 6, 2, 6 }, //Here i want this to be filled with data from AppropriateLine variable, it works for the fixed value only
Fill = "false",
LineTension = 0.1,
BackgroundColor = ChartColor.FromHexString("#FF6384"),
BorderColor = ChartColor.FromHexString("#FF6384"),
BorderCapStyle = "butt",
BorderDash = new List<int> { },
BorderDashOffset = 0.0,
BorderJoinStyle = "miter",
PointBorderColor = new List<ChartColor>() { ChartColor.FromHexString("#FF6384"), },
PointBackgroundColor = new List<ChartColor>() { ChartColor.FromHexString("#fff") },
PointBorderWidth = new List<int> { 1 },
PointHoverRadius = new List<int> { 5 },
PointHoverBackgroundColor = new List<ChartColor>() { ChartColor.FromHexString("#FF6384"), },
PointHoverBorderColor = new List<ChartColor>() { ChartColor.FromHexString("#FF6384"), },
PointHoverBorderWidth = new List<int> { 2 },
PointRadius = new List<int> { 1 },
PointHitRadius = new List<int> { 10 },
SpanGaps = false
};
data.Datasets = new List<Dataset>();
data.Datasets.Add(AppropriateDataset);
Options options = new Options()
{
Scales = new Scales()
};
Scales scales = new Scales()
{
YAxes = new List<Scale>()
{
new CartesianScale()
}
};
CartesianScale yAxes = new CartesianScale()
{
Ticks = new Tick()
};
Tick tick = new Tick()
{
Callback = "function(value, index, values) {return '' + value;}"
};
yAxes.Ticks = tick;
scales.YAxes = new List<Scale>() { yAxes };
options.Scales = scales;
chart.Options = options;
chart.Data = data;
return chart;
}
How can i implement this "Explicit Casting" of appropriateLine variable which is (int) before passing it to GenerateLineChart().
Note that i don't want to change Model properties type since many functions depend on it. Also, I cannot change Data type from List<double?> since many other problems solved by adding this.
I tried many casting solutions but none of them works for me such as:
(List<double?>)result.Select(x => x.Appropriate);
private static Chart GenerateLineChart((List<double?>)AppropriateLine)
I've read about "Convert all" method but not worked.
Any help is much appreciated,
Thanks in advance.
Based on what you mention, it seems that the data passed to GenerateLineChart will only be used for UI purposes. That is, this method can get an appropriate copy of the original data. If this is the case, then, the solution you attempted with
(List<double?>)result.Select(x => x.Appropriate)
was very close, but the cast needs to be done inside Select, i.e.
result.Select(x => (double?)x.Appropriate)
Here is a sketch of your code with that change
public IActionResult Details()
{
var result = _db.Session.ToList();
var AppropriateLine = result.Select(x => (double?)x.Appropriate).ToList();
var lineChart = GenerateLineChart(AppropriateLine);
// Rest or your code
}
private static Chart GenerateLineChart(IEnumerable<double?> data)
{
// Your code as is here ....
LineDataset AppropriateDataset = new LineDataset()
{
Data = data,
// Rest of your code
}
// ....
}
maybe you can check at the moment that you need the list if the number is double or int bool isInt = d == (int)d; and parse to use it only for that time on an aux.

Cartesian Product of an arbitrary number of objects [duplicate]

This question already has answers here:
Is there a good LINQ way to do a cartesian product?
(3 answers)
Closed 4 years ago.
I'm looking to get the Cartesian Product of an arbitrary number of objects in c#. My situation is slightly unusual - my inputs are not lists of base types, but objects which have a property that's a list of base types.
My input and output objects are as follows:
public class Input
{
public string Label;
public List<int> Ids;
}
public class Result
{
public string Label;
public int Id;
}
Some sample input data:
var inputs = new List<Input>
{
new Input { Label = "List1", Ids = new List<int>{ 1, 2 } },
new Input { Label = "List2", Ids = new List<int>{ 2, 3 } },
new Input { Label = "List3", Ids = new List<int>{ 4 } }
};
And my expected output object:
var expectedResult = new List<List<Result>>
{
new List<Result>
{
new Result{Label = "List1", Id = 1},
new Result{Label = "List2", Id = 2},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 1},
new Result{Label = "List2", Id = 3},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 2},
new Result{Label = "List2", Id = 2},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 2},
new Result{Label = "List2", Id = 3},
new Result{Label = "List3", Id = 4}
}
};
If I knew the number of items in 'inputs' in advance I could do this:
var knownInputResult =
from id1 in inputs[0].Ids
from id2 in inputs[1].Ids
from id3 in inputs[2].Ids
select
new List<Result>
{
new Result { Id = id1, Label = inputs[0].Label },
new Result { Id = id2, Label = inputs[1].Label },
new Result { Id = id3, Label = inputs[2].Label },
};
I'm struggling to adapt this to an arbitrary number of inputs - is there a possible way to do this?
I consider this duplicate of question linked in comments, but since it was reopened and you struggle to adapt that question to your case, here is how.
First grab function by Eric Lippert from duplicate question as is (how it works is explained there):
public static class Extensions {
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item })
);
}
}
Then flatten your input. Basically just attach corresponding label to each id:
var flatten = inputs.Select(c => c.Ids.Select(r => new Result {Label = c.Label, Id = r}));
Then run cartesian product and done:
// your expected result
var result = flatten.CartesianProduct().Select(r => r.ToList()).ToList();
I'm not proud of the amount of time I spent messing with this, but it works.
It's basically black magic, and I would replace it the first chance you get.
public static List<List<Result>> Permutate(IEnumerable<Input> inputs)
{
List<List<Result>> results = new List<List<Result>>();
var size = inputs.Select(inp => factorial_WhileLoop(inp.Ids.Count)).Aggregate((item, carry) => item + carry) - 1;
for (int i = 0; i < size; i++) results.Add(new List<Result>());
foreach (var input in inputs)
{
for (int j = 0; j < input.Ids.Count; j++)
{
for (int i = 0; i < (size / input.Ids.Count); i++)
{
var x = new Result() { Label = input.Label, Id = input.Ids[j] };
results[(input.Ids.Count * i) + j].Add(x);
}
}
}
return results;
}
public static int factorial_WhileLoop(int number)
{
var result = 1;
while (number != 1)
{
result = result * number;
number = number - 1;
}
return result;
}

Why does using IEnumerable<T> inside a recursive method make it much slower than using a List<T>?

I am using a recursive method to go through a tree of items and add its children to a flat collection:
public class Thing
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
}
void Main()
{
var sampleData = new List<Thing>
{
new Thing { Id = 1, Name = "root1", ParentId = null },
new Thing { Id = 2, Name = "2", ParentId = 1 },
new Thing { Id = 3, Name = "3", ParentId = 1 },
new Thing { Id = 4, Name = "4", ParentId = 2 },
new Thing { Id = 5, Name = "5", ParentId = 2 },
new Thing { Id = 6, Name = "6", ParentId = 2 },
new Thing { Id = 7, Name = "7", ParentId = 6 },
new Thing { Id = 8, Name = "8", ParentId = 7 },
new Thing { Id = 9, Name = "9", ParentId = 8 },
new Thing { Id = 10, Name = "10", ParentId = 9 },
new Thing { Id = 11, Name = "11", ParentId = 10 },
new Thing { Id = 12, Name = "12", ParentId = 11 },
new Thing { Id = 13, Name = "13", ParentId = 12 },
new Thing { Id = 14, Name = "14", ParentId = 13 },
new Thing { Id = 15, Name = "root15", ParentId = null }
};
var subThings = new HashSet<Thing>();
var stopWatch = new Stopwatch();
stopWatch.Start();
//AddSubThings(subThings, sampleData, new List<int> { 1 });
AddSubThingsUsingList(subThings, sampleData, new List<int> { 1 });
stopWatch.Elapsed.Dump();
subThings.Dump();
}
private void AddSubThings(HashSet<Thing> resultThings, IEnumerable<Thing> sourceThings, IEnumerable<int> parentIds)
{
if (!sourceThings.Any() || !parentIds.Any())
{
return;
}
var subThings = sourceThings.Where(st => st.ParentId.HasValue && parentIds.Contains(st.ParentId.Value));
resultThings.UnionWith(subThings);
AddSubThings(resultThings, sourceThings.Except(subThings), subThings.Select(st => st.Id));
}
private void AddSubThingsUsingList(HashSet<Thing> resultThings, List<Thing> sourceThings, List<int> parentIds)
{
if (!sourceThings.Any() || !parentIds.Any())
{
return;
}
var subThings = sourceThings.Where(st => st.ParentId.HasValue && parentIds.Contains(st.ParentId.Value));
resultThings.UnionWith(subThings);
AddSubThingsUsingList(resultThings, sourceThings.Except(subThings).ToList(), subThings.Select(st => st.Id).ToList());
}
When I use the AddSubThings method it takes around 90 seconds to process. However if I use the AddSubThingsUsingList method it does not even take a second. Why is this?
The problem is because your create subThings from sourceThings like this
var subThings = sourceThings.Where(
st => st.ParentId.HasValue && parentIds.Contains(st.ParentId.Value));
Then you pass the following as sourceThings to the recursive call.
sourceThings.Except(subThings)
Which is equivalent to
sourceThings.Except(
sourceThings.Where(
st => st.ParentId.HasValue && parentIds.Contains(st.ParentId.Value)))
That query when iterated with have to iterate over the original list twice. With each recursive call the query will build up and need to iterate the original list 2^n times where n is the recursion level. And your query is being iterated by the Any and the HashSet.UnionWith calls meaning it's more like 2^(n+1).
The other one immediately iterates the query before passing them and thus avoids this doubling problem.
You could pass the following to your recursive call for sourceThings instead to make it faster as it doesn't double up the required iterating of the original list on each recursive call.
sourceThings.Where(st => !st.ParentId.HasValue || !parentIds.Contains(st.ParentId.Value))
Ok. This is a bit complex.
Operations on IEnumerable are lazy, i.e. they are not executed until you need the result. Now when you pass sourceThins and subThings to AddSubThings, you've not sent a materialized collection of things, all you've done is you've defined how these collections are calculated from the original Lists.
Now when the method calls itself recursively, it adds more filtering and selection to the data it has received.
All these layers of selection and filtering will be called when you call Any().
On the other hand, in the case of Lists, things are materialized after calls to Where, Except and Select, because you call ToList.

how to sort a list then sort a subset of that list

I have a collection of lines. Each line is a collection of fields. It is very easy to find column 1 and sort by its content:
_lines = lines.OrderBy(l => l.Fields.Find(f => f.ColumnNumber == 1).Content).ToList();
But how do I then sort a subset of this list? I want to sort by f.ColumnNumber == 3 where (f.ColumnNumber == 1).Content is 6.
So my line collection looks like this:
Col1, Col2, Col3
1, data, data
5, data, data
6, data, Chuck
6, data, Chuck
6, data, Jeffster
6, data, Jeffster
6, data, Grunke
6, data, Gertrude
8, data, data
9, data, data
I want to sort by col1, then sort only col1's where col1 == 6 but sort by col3.
Is there a way to do this in c#? I can't seem to find the magic formula.
EDIT:
My sample data is a little over simplified. Some lines have 3 columns, other lines have more or less columns. So when I use the .ThenBy extention, if I am trying to subsort lines on col 3 but say line 9 only has one column, I get an object reference not set to an instance of an object exception.
Here is a better example of the sample data:
Col1, Col2, Col3, Col4
1, data, data, data
5, data, data
6, data, Chuck
6, data, Chuck
6, data, Jeffster
6, data, Jeffster
6, data, Grunke
6, data, Gertrude
8, data, data
9, data
Code 1 lines have 4 columns.
Code 5 lines have 3.
Code 6 lines have 3 - and I need to sort by col 3 alphabetically.
Code 8 lines have 3 columns.
Code 9 lines have 2.
There is no guarantee the list is sorted at all. So I need first of all to have the lines sorted by that first column 1 - 9, then I need only code 6's to be sorted by col 3.
EDIT 2:
My class structure is somewhat complicated so I was trying to keep it simple as possible hoping it would be sufficient, but it looks like that his not the case so let me share with you the class definition:
public class Field : IField
{
public FieldSpecification Specification { get; set; }
public string Content { get; set; }
}
public class FieldSpecification
{
public int ColumnNumber { get; set; }
public int Length { get; set; }
public int StartPosition { get; set; }
public int EndPosition { get { return StartPosition + Length - 1; } }
public Justification Justification { get; set; }
public char PadCharacter { get; set; }
}
Then I have a bunch of lines that conform to the ILine interface
public interface ILine
{
List<IField> Fields { get; set; }
int Credits { get; }
int Debits { get; }
BigInteger Hash { get; }
}
So technically above I show something like field.ColumnNumber, but it should be field.Specification.ColumnNumber.
The objective is to build fixed width files according to specifications that can change. So each line has a collection of fields with specifications, and then data can go into the content, and the specification can help do validation: formatting validation.
I was hoping there would be a way to sort subsets of lists using linq, but I may need to deconstruct my final collection of lines, sort it, then reconstruct the collection. I was hoping to avoid that.
You could use the ThenBy extension.
Looking at your desired output, it seems something as simple as,
var output = lines.Select(l => new
{
Col1 = int.Parse(l.Fields.Find(f => f.ColumnNumber == 1).Content),
Col2 = l.Fields.Find(f => f.ColumnNumber == 2).Content,
Col3 = l.Fields.Find(f => f.ColumnNumber == 3).Content
}).OrderBy(l => l.Col1).ThenBy(l => l.Col3);
would suffice.
If, for some reason, you only want to order the sub list when Col1 is 6,
var output = lines.Select(l => new
{
Col1 = int.Parse(l.Fields.Find(f => f.ColumnNumber == 1).Content),
Col2 = l.Fields.Find(f => f.ColumnNumber == 2).Content,
Col3 = l.Fields.Find(f => f.ColumnNumber == 3).Content
}).OrderBy(l => l.Col1).ThenBy(l => l.Col1 == 6 ? l.Col3 : null);
One last caveat, depending on the type of Fields there is probably a better approach to all of this.
It can be done via the ThenBy extension method; in general, the concept is known as lexicographical order.
If I can assume that you class definition is this:
public class Datum
{
public int ID { get; set; }
public string[] Cols { get; set; }
}
Then I can define the data like this:
var data = new []
{
new Datum() { ID = 1, Cols = new [] { "data", "data", "data", }, },
new Datum() { ID = 5, Cols = new [] { "data", "data", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Chuck", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Chuck", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Jeffster", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Jeffster", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Grunke", }, },
new Datum() { ID = 6, Cols = new [] { "data", "Gertrude", }, },
new Datum() { ID = 8, Cols = new [] { "data", "data", }, },
new Datum() { ID = 9, Cols = new [] { "data", }, },
};
And then I can sort like this:
var sorted =
from d in data
let key =
String.Format("{0:0000}", d.ID)
+ (d.ID != 6 ? "" : "-" + d.Cols[1])
orderby key
select d;
I get these results:

Categories