How to sequence my data table using linq - linq

I have a DataTable that looks like below:
| ItemName | ItemPro
A HWH
A BRB
A EAH
B HWH
B BRB
B EAH
B HWH
C BRB
C EAH
I want to group above DataTable by ItemName and sort these groups
How can I achieve this?
Note: after sorting, I want my table like below;
| ItemName | ItemPro
A HWH
B BRB
c EAH
A HWH
B BRB
C EAH
A HWH
B BRB
B EAH

You don't have to group your values by ItemName instead you can apply sorting on ItemName like:
var sortedQuery = dt.AsEnumerable()
.OrderBy(r=> r.Field<string>("ItemName"));
If you want the second field to be sorted as well then use Enumerable.ThenBy like:
var sortedQuery = dt.AsEnumerable()
.OrderBy(r => r.Field<string>("ItemName"))
.ThenBy(r => r.Field<string>("ItemPro"));
If you want result in a new DataTable then:
DataTable sortedDt = dt.AsEnumerable()
.OrderBy(r => r.Field<string>("ItemName"))
.ThenBy(r => r.Field<string>("ItemPro"))
.CopyToDataTable();

var listOfStrings = new List{
"Orange",
"Orange",
"Orange",
"Orange",
"Mango",
"Mango",
"Mango",
"Mango",
"Mango",
"Mango",
"Apple",
"Apple",
"Apple"
};
var groupedStrings = listOfStrings.GroupBy(i => i)
.Select(i => new { i.Key, Items = i.ToList() }).ToList();
var maxGroupSize = groupedStrings.OrderByDescending(i => i.Items.Count).First()
.Items.Count;
var finalList = new List<string>();
for (var i = 0; i < maxGroupSize; i++)
{
finalList.AddRange(from wordGroup in groupedStrings
where i < wordGroup.Items.Count
select wordGroup.Items[i]);
}

Related

How to subtract the two columns sum of amount using linq

Below my query which not working properly could any one help here?
enter code here
var collectionamount = (from u in db.bank_deposit
join pr in db.collections on u.AgentID equals pr.AgentID into g
join agentname in db.agent_master on u.AgentID equals agentname.AgentID
group u by new { u.AgentID } into x
select new collectionwithdeposit
{
AgentName = agentname.AgentName,
DepositedAmount = g.Sum(m => m.DepositedAmount),
CollectionAmount = g.Sum(z => z.AmountReceived),
Balance = g.Sum(u => u.DepositedAmount) - g.Sum(v => v.AmountReceived)
}).ToList();
lstdataModel.Add(dataModel);
}
The variable g does not exists in the scope of your select. This is because of the into keyword. What you are writing is in effect..
var tempEnumerable = from u in db.bank_deposit
join pr in db.collections on u.AgentID equals pr.AgentID into g
join agentname in db.agent_master on u.AgentID equals agentname.AgentID
group u by new { u.AgentID };
var collectionamount = from x in tempEnumerable
select new collectionwithdeposit
{
AgentName = agentname.AgentName,
DepositedAmount = g.Sum(m => m.DepositedAmount),
CollectionAmount = g.Sum(z => z.AmountReceived),
Balance = g.Sum(u => u.DepositedAmount) - g.Sum(v => v.AmountReceived)
}).ToList();
The into keyword in Linq is for creating a new scope.
In fact you really don't want to use into as often as you do
Try this
var collectionAmount = from u in db.bank_deposit
where db.collections.Any(pr => pr.AgentID == u.AgentID)
join agentname in db.agent_master on u.AgentID equals agentname.AgentID
group u by agentname into g
select new collectionwithdeposit
{
AgentName = g.Key.AgentName,
DepositedAmount = g.Sum(m => m.DepositedAmount),
CollectionAmount = g.Sum(z => z.AmountReceived),
Balance = g.Sum(u => u.DepositedAmount) - g.Sum(v => v.AmountReceived)
}
EDITED:
Maybe actually what you want is this...I don't know your table structures. But I am going to assume you have no idea about Linq, and your tables are sane (since my last answer assumed the opposite).
var collectionAmount = from agent in db.agent_master
let depositedAmount = db.bank_deposit
.Where(d => d.AgentID == agent.AgentID)
.Sum(d => c.DepositedAmount)
let collectionAmount = db.collections
.Where(c => c.AgentID == agent.AgentID)
.Sum(c => c.AmountReceived)
select new collectionwithdeposit
{
AgentName = agent.AgentName,
DepositedAmount = depositedAmount,
CollectionAmount = collectionAmount,
Balance = depositedAmount - collectionAmount
}

Linq select top 1 name of a highest score group

I have a list which is like below
Name Score Date
S1 2 15/02/2013
S1 4 15/02/2013
S2 0 15/02/2013
My desired out should be
S1 6 15/02/2013
for this i wrote LINQ code as
(from _data in _rawData
group _data by new { _data.Date, _data.Name } into gp orderby gp.Key.Date
select new
{
score = gp.Sum(_score => _score.Score),
store = gp.Max(_store => _store.Name),
Date = gp.Max(_Date => _Date.Date)
}).OrderByDescending(_score => _score.score)
.ToList().
ForEach(item => _timeLiner.Add(new TimeLiner()
{
id = _id++.ToString(),
start = item.auditDate.ToString(),
title = "TopStore: " + item.store
}
I tried with .Take(1).ToList(), Single(), SingleOrDefault(), First() but i failed to get desired output. Instead i am getting as
S1 6 15/02/2013
S2 0 15/02/2013
top is a new range variable, which holds summary data for top score name of a day
from d in _rawData
group d by d.Date into dateGroup
let top = dateGroup.GroupBy(x => x.Name)
.Select(g => new { Name = g.Key, Score = g.Sum(x => x.Score)})
.OrderByDescending(x => x.Score)
.First()
select new
{
Name = top.Name,
Score = top.Score,
Date = dateGroup.Key
}
The following should give you the desired output:
(from _data in _rawData
group _data by new { _data.Date, _data.Name } into gp orderby gp.Key.Date
select new
{
score = gp.Sum(_score => _score.Score),
store = gp.Max(_store => _store.Name),
Date = gp.Max(_Date => _Date.Date)
}).OrderByDescending(_score => _score.score)
.First();
Or, a little bit more readable:
_rawData.GroupBy(x => new { x.Date, x.Name })
.Select(g => new {
Score = g.Sum(x => x.Score),
Store = g.Key.Name,
Date = g.Key.Date
}
.OrderByDescending(x => x.Score)
.First()

linq groupjoin using lambda with a where clause

I need to add a join using Lambda if I have a further parameter available that will also be used in a where clause.
My problem is I'm not sure of the exact format for adding a new object MemberTagLysts and then how the where clause should be created.
var tagList = from t in dc.Tags
join b in dc.Businesses on t.BusinessId equals b.BusinessId
where t.IsActive == true
where b.IsActive == true
orderby t.AdImage descending
select new TagItem
{
tagName = t.Name.Replace("\"", ""),
tagImage = tagImagePath + t.AdImage.Replace("\"", ""),
tagDescription = t.Description.Replace("\"", "")
};
if (!string.IsNullOrEmpty(lystId))
{
tagList = (IQueryable<TagItem>)tagList.GroupJoin(dc.MemberTagLysts, a => a.tagId, b => b.TagId, (a, b) => new { a, b });
}
I think you want to do something like this:
var tagList = from t in dc.Tags
join b in dc.Businesses on t.BusinessId equals b.BusinessId
where t.IsActive
where b.IsActive
orderby t.AdImage descending
select new TagItem
{
tagName = t.Name.Replace("\"", ""),
tagImage = tagImagePath + t.AdImage.Replace("\"", ""),
tagDescription = t.Description.Replace("\"", "")
};
if (!string.IsNullOrEmpty(lystId))
{
tagList = tagList
.GroupJoin(dc.MemberTagLysts.Where(l => l.lystId == lystId),
a => a.tagId,
b => b.TagId,
(a, b) => new { a, b }));
}
Conditionally expanding the query is good practice. Note that conditions like where t.IsActive == true are redundant, where t.IsActive is enough and arguable better readable with well-chosen property names (as you have).

Convert multiple rows into single in datatable

I have a DataTable in C# with two columns
State Region
A 1
A 2
B 3
B 4
What I want to achieve is
State Region
A 1,2
B 3,4
Is this possible in C# with a single LINQ query?
I am not good in LINQ and also don't want to loop through table to achieve that.
var result = dataTable.AsEnumerable()
.GroupBy(row => row.Field<string>("State"))
.Select(g =>
{
var row = dataTable.NewRow();
row.ItemArray = new object[]
{
g.Key,
string.Join(",",
g.Select(r => r.Field<string>("Region")))
};
return row;
}).CopyToDataTable();
Use GroupBy to achieve this as follow....
var groupedData = from b in dataTable.AsEnumerable()
group b by b.Field<string>("State") into g
select new
{
State = g.Key,
Regions = g,
};
Then you can iterate through each group to get Data...
foreach (var g in groupedData)
{
foreach (var w in g.Regions)
{
Console.WriteLine(w);
}
}

Update existing list values with values from another query

I have a linq statement which calls a stored proc and returns a list of items and descriptions.
Like so;
var q = from i in doh.usp_Report_PLC()
where i.QTYGood == 0
orderby i.PartNumber
select new Parts() { PartNumber = i.PartNumber, Description = i.Descritpion.TrimEnd() };
I then have another SQL statement which returns the quantities on order and delivery date for each of those items. The Parts class has two other properties to store these. How do I update the existing Parts list with the other two values so that there is one Parts list with all four values?
UPDATE
The following code now brings out results.
var a = from a1 in db.usp_Optos_DaysOnHand_Report_PLC()
where a1.QTYGood == 0
orderby a1.PartNumber
select new Parts() { PartNumber = a1.PartNumber, Description = a1.Descritpion.TrimEnd() };
var b = from b1 in db.POP10110s
join b2 in db.IV00101s on b1.ITEMNMBR equals b2.ITEMNMBR
//from b3 in j1.DefaultIfEmpty()
where b1.POLNESTA == 2 && b1.QTYCANCE == 0
group b1 by new { itemNumber = b2.ITMGEDSC } into g
select new Parts() { PartNumber = g.Key.itemNumber.TrimEnd(), QtyOnOrder = g.Sum(x => Convert.ToInt32(x.QTYORDER)), DeliveryDue = g.Max(x => x.REQDATE).ToShortDateString() };
var joinedList = a.Join(b,
usp => usp.PartNumber,
oss => oss.PartNumber,
(usp, oss) =>
new Parts
{
PartNumber = usp.PartNumber,
Description = usp.Description,
QtyOnOrder = oss.QtyOnOrder,
DeliveryDue = oss.DeliveryDue
});
return joinedList.ToList();
Assuming your "other SQL statement" returns PartNumber, Quantity and DeliveryDate, you can join the lists into one:
var joinedList = q.Join(OtherSQLStatement(),
usp => usp.PartNumber,
oss => oss.PartNumber,
(usp, oss) =>
new Parts
{
PartNumber = usp.PartNumber,
Description = usp.Description,
Quantity = oss.Quantity,
DeliveryDate = oss.DeliveryDate
}).ToList();
You can actually combine the queries and do this in one join and projection:
var joinedList = doh.usp_Report_PLC().
Where(i => i.QTYGood == 0).
OrderBy(i => i.PartNumber).
Join(OtherSQLStatement(),
i => i.PartNumber,
o => o.PartNumber,
(i, o) =>
new Parts
{
PartNumber = i.PartNumber,
Description = i.Description,
Quantity = o.Quantity,
DeliveryDate = o.DeliveryDate
}).ToList();
And again: I assume you have PartNumber in both returned collections to identify which item belongs to which.
Edit
In this case the LINQ Query syntax would probably be more readable:
var joinedList = from aElem in a
join bElem in b
on aElem.PartNumber equals bElem.PartNumber into joinedAB
from abElem in joinedAB.DefaultIfEmpty()
select new Part
{
PartNumber = aElem.PartNumber,
Description = aElem.Description,
DeliveryDue = abElem == null ? null : abElem.DeliveryDue,
QtyOnOrder = abElem == null ? null : abElem.QtyOnOrder
};
Your DeliveryDue and QtyOnOrder are probably nullable. If not, replace the nulls by your default values. E.g. if you don't have the element in b and want QtyOnOrder to be 0 in the resulting list, change the line to
QtyOnOrder = abElem == null ? 0 : abElem.QtyOnOrder

Resources