Sort column in DataTable with same values - c#

I have a question about sorting in Datatable. I have a table like below and want to sort it from small to big. The problem is when i have same numbers, i want to have the first as the last and so on...
Table:-----------------------------------After Sorting:
Name Bit Size Name Bit Size (corrected)
A 0 1 A 0 1
C 1 2 C 1 2
B 1 3 B 1 3
D 1 1 D 1 1
Result that i want:
Name Bit Size (corrected)
A 0 1
D 1 1
B 1 3
C 1 2
My Code:
arraySBit.DefaultView.Sort = "Bit";
arraySBit = arraySBit.DefaultView.ToTable();

You can use Linq-To-DataTable:
var tblSorted = table.AsEnumerable()
.OrderBy(r => r.Field<int>("Bit"))
.CopyToDataTable();
Edit: But actually DataView.Sort should also work (tested).
Since you have edited your question. Your requirement seems weired. If the Bit is the same you don't want to order by something but you want to reverse the "order" of the rows of the equal rows (so the Ordinal position in the DataTable).
This does what you want although i'm not sure that it's really what you need:
DataTable tblSorted = table.AsEnumerable()
.Select((Row, Ordinal) => new {Row,Ordinal})
.OrderBy(x => x.Row.Field<int>("Bit"))
.ThenByDescending(x => x.Ordinal)
.Select(x => x.Row)
.CopyToDataTable();
Basically it passes the index of the row in the table via this overload Enumerable.Select into an anonymous type. Then it'll sort by Bit first and the index/ordinal second.

A workaround,
After these lines, you should have result in arrySBit as you want
DataTable arrySBitClone = arrySBit.Copy();
arrySBit.DefaultViewSort.Sort = "Bit";
bool different = false;
for(int i=0; i<arrySBit.Rows.Count; i++)
{
if(arrySBit.Rows[i]["Bit"]!=arrySBitClone.Rows[i]["Bit"])
{
difference = true;
break;
}
}
if(!different)
{
arrySBit = arrySBit.Copy();
}

if i'm getting right your question.
why not use Select?
DataTable dt = arraySBit.Select("", "Bit, Size").CopyToDataTable();
The first parameter of the Select Method is a condition to filter, the second is an Order By, so it should work

Related

reorder datatable rows with a specific sequence of values

I have a datatable that looks like this:
IDDOC DOCNAME
1 mydoc1
153 mydoc2
98 mydoc3
1327 mydoc4
241 mydoc5
I would like to find a way to reorder the rows in that datatable by basing on a specific sequence of ID
For example, with a sequence like this : 1327,98,1 the expected output would be :
IDDOC DOCNAME
1327 mydoc4
98 mydoc3
1 mydoc1
153 mydoc2 (not in my sequence so this row comes at the end)
241 mydoc5 (not in my sequence so this row comes at the end)
I was thinking about creating a new empty database and adding the row with the IDDOC coming first, then second, then third in the sequence, then finally all the rows not present in my sequence but i was wondering if something cleaner already existed.
Thank you a lot for your help!
You could use this approach:
dt = dt.AsEnumerable()
.OrderBy(r => r.Field<int>("IDDOC") == 1327 ? 0 : 1)
.ThenBy(r => r.Field<int>("IDDOC") == 98 ? 0 : 1)
.ThenBy(r => r.Field<int>("IDDOC") == 1 ? 0 : 1)
.CopyToDataTable();
If you want a dynamic list of id's and the DataTable should be ordered by this sequence:
List<int> docIdSequence = new List<int>{ 1327, 98, 1 };
dt = dt.AsEnumerable()
.OrderBy(r => {
int ix = docIdSequence.IndexOf(r.Field<int>("IDDOC"));
return ix >= 0 ? ix : int.MaxValue;
})
.CopyToDataTable();
Note that CopyToDataTable throws an exception if there are no input DataRows. So you have to check if dt.Rows.Count > 0 before you use above code.

First time using lambda function on c#

Hello everyone this is my first time asking a question on stack overflow, so I'll be as descriptive as possible. I've been trying to wrap my head around the lambda function and I think that this would be an appropriate time to use the function.
I have an sql table with a column machineNo and another column named count as a flag of yes or no whether its counted or not.
My objective is to group columns based on the machineNo column in sql. I've returned the list from sql with no problems.
I have
Spot 2
Spot 1
Spot 1
Spot 1
Spot 1
Its supposed to show e.g
lbl1.Text = 4
lbl2.Text = 1
public void listlambda()
{
con.OpenConnection();
List<string> mchno = con.LoadList("Select mchNo from tbl_mch_ability where count = 0", "mchNo");
var num = mchno.GroupBy(n => n == "mchNo");
lbl1.Text = mchno.GroupBy(m => m == "Spot 1").Count().ToString();
lbl2.Text = mchno.GroupBy(m => m == "Spot 2").Count().ToString();
}
I've tried a lot of examples from stack overflow but my label always shows two.
You can not apply == on IGrouping. You need to change the groupBy as
var num = mchno.GroupBy(n => n);
and later the text box assignment as
lbl1.Text = num .Count(m => m == "Spot 1").ToString();
lbl2.Text = num .Count(m => m == "Spot 2").ToString();

c# calculate distinct value in datatable

what i have in my datatable
Resource
1 // 1 represent normal
1
2 // 2 represent sql
2
3 // 3 css
4 // 4 unicode
4
4
how can i perform calculation so that i could display the value in a textbox
normal 2
sql 2
css 1
unicode 3
total hits 9
what ive tried so far
var result = my_datatable.AsEnumerable().Sum(x => Convert.ToInt32(x["Resource"]));
string result2 = result.ToString();
totalTxtBox.Text = result2;
but it calculate the whole column (output is: 24 instead of 9)
Use the following example-
int[] res = { 1,1,2,2,3,4,4,4};
var words = res.AsEnumerable().GroupBy(x => x);
foreach (var x in words)
{
Console.WriteLine(x.Key+"-"+x.Count());
}
It will print output as-
1-2
2-2
3-1
4-3
You can try to use Distinct()
var result = my_datatable.AsEnumerable().Distinct().Sum(x => Convert.ToInt32(x["Resource"]));
Distinct() Returns distinct elements from a sequence by using the default equality comparer to compare values.
for more info: https://msdn.microsoft.com/en-us/library/bb348436(v=vs.110).aspx
You can try to use this example as your reference. Firstly, I get the Distinct values from the datatable and converted it to list and then use the sum function.
Updated Answer:
DataTable my_datatable = new DataTable();
my_datatable.Columns.Add("Value", typeof(int));
my_datatable.Columns.Add("Type", typeof(string));
my_datatable.Rows.Add(1, "Normal");
my_datatable.Rows.Add(1, "Normal");
my_datatable.Rows.Add(2, "SQL");
my_datatable.Rows.Add(2, "SQL");
my_datatable.Rows.Add(3, "CSS");
my_datatable.Rows.Add(4, "UNICODE");
my_datatable.Rows.Add(4, "UNICODE");
my_datatable.Rows.Add(4, "UNICODE");
var distinctIds = my_datatable.AsEnumerable()
.Select(s => new {
value = s.Field<int>("value"),
})
.Distinct().ToList();
int total = distinctIds.Sum(item => item.value);
I figured it out by myself
use this line (linq) in order to filter out which value you want
int normalcount = my_datatable
.AsEnumerable()
.Where(r => r.Field<string>("Resource") == "1")
.Count();
try to change this line to filter out which value, according to your column value
.Where(r => r.Field<string>("Resource") == "2")
.Count();

Linq How to combine two List's columns

Please Help me in the following...
I have two list objects as follows:
list1:
ID col1
--------
1 A
1 B
1 C
list2:
ID col2
--------
1 D
1 E
1 F
Now I want:
ID col1 col2
---------------
1 A D
1 B E
1 C F
So basically column1 then column 2 from list1 then column 3 from list 2. Column1 is common.
Please note that the number of rows may not be always same.. in that case it will be null.
I really really need this solution in Linq. Thanks.
List<Class> list1 = new List<Class>();
List<Class> list2 = new List<Class>();
// Add classes to lists...
list1.AddRange(list2);
// Order merged list...
list1.OrderByDescending(o => o.col1).ThenBy(o => o.col2);
Trying to understand...
Dictionary<Int32, Class[]> dictionary = new Dictionary<Int32, Class[]>();
list2.Reverse();
for (Int32 i = 0; i < list1.Count; ++i)
dictionary[i] = new Class[2] { list1[i], list2[i] };
I really donĀ“t understand why was hard for get clear the question, he only want have two array combined in one (still i don't know why in the aswers of the web you only find Concat,AddRange or Union. Wrong Answers For this Question):
I solve it with Zip:
var result = list1.Zip(list2,(first,second)=>new {entrada=first,salida=second});
Now You Can do Something like this:
var union=result.Select(x=> new {x.entrada, x.salida, horas = int.Parse((DateTime.Parse(x.salida).Subtract(DateTime.Parse(x.entrada))).Hours.ToString()) });

Get min value in row during LINQ query

I know that I can use .Min() to get minimum value from column, but how to get minimum value in a row?
I have following LINQ query (for testing purposes):
from p in Pravidloes
where p.DulezitostId == 3
where p.ZpozdeniId == 1 || p.ZpozdeniId == 2
where p.SpolehlivostId == 2 || p.SpolehlivostId == 3
group p by p.VysledekId into g
select new {
result = g.Key,
value = g
}
Which results into this:
I would however like to get only the MIN value of following three columns:
DulezitostId, ZpozdeniId, SpolehlivostId as a value in:
select new {
result = g.Key,
value = g // <-- here
}
The final result then should look like:
result: 2, value: 1
result: 3, value: 2
I have been looking for similar questions here and googled for few examples with grouping and aggregating queries, but found nothing that would move me forward with this problem.
Btw: Solution isn't limited to linq, if you know better way how to do it.
You could create an array of the values and do Min on those.
select new {
result = g.Key,
value = g.SelectMany(x => new int[] { x.DulezitostId, x.ZpozdeniId, x.SpolehlivostId }).Min()
}
This will return the min for those 3 values in each grouping for ALL rows of that grouping.
Which would result in something like this...
result: 3, value: 1
The below will select the min for each row in the grouping...
select new {
result = g.Key,
value = g.Select(x => new int[] { x.DulezitostId, x.ZpozdeniId, x.SpolehlivostId }.Min())
}
Which would result in something like this...
result: 3, value: 1, 2
The best solution if you're using straight LINQ is Chad's answer. However, if you're using Linq To SQL it won't work because you can't construct an array like that.
Unfortunately, I believe the only way to do this in Linq To Sql is to use Math.Min repeatedly:
select new {
result = g.Key,
value = Math.Min(Math.Min(DulezitostId, ZpozdeniId), SpolehlivostId)
}
This will generate some ugly CASE WHEN ... statements, but it works.
The main advantage of doing it this way is that you're only returning the data you need from SQL (instead of returning all 3 columns and doing the Min in the application).

Categories