using one query values in another query - c#

// To get current user id
var currentUsrId = Convert.ToInt16(Membership.GetUser().ProviderUserKey);
var IDquery = My_usr_contacts_requests.Where(i => i.requests_to_usr_id == currentUsrId)
.Select(i => new { i.from_usr_id })
.ToArray();
var mainquery = My_usr_biographic_details
.Join(
My_usr_profiles_companies, i => i.usr_id, j => j.company_usr_id,
(i, j) => new
{
usr_id = j.company_usr_id,
})
.Where(i =>IDquery.contains(i.usr_id))
.ToArray();
while I am executing I am getting array of values in IDquery, and I want to use these values in the where condition of mainquery as shown above, but when I give like this it showing error at the mainquery where condition. Can you tell me how to use the array of values retrieved from IDquery in mainquery?

You wrote:
var IDquery = dbContext.My_usr_contacts_requests.Where(i =>
i.Usr_contacts_requests_to_usr_id==currentUsrId).Select(i => new {
i.Usr_contacts_requests_from_usr_id }).ToArray();
The last new is unnecessary. It creates an array of arrays. You need to change it to:
var IDquery = dbContext.My_usr_contacts_requests.Where(i =>
i.Usr_contacts_requests_to_usr_id==currentUsrId).Select(i =>
i.Usr_contacts_requests_from_usr_id).ToArray();

Related

Preserve order with linq after groupby and selectmany

Is there a way to preserve the order after this linq expression?
var results =
DateList
.GroupBy(x => x.Date.Subtract(firstDay).Days / 7 + 1)
.SelectMany(gx => gx, (gx, x) => new {Week = gx.Key,DateTime =x,Count = gx.Count(),});
I found this Preserving order with LINQ , but I'm not sure if its the GroupBy or SelectMany casing the issues
Yes, if you first select your DateList and combine it with an index, using an overload of .Select that uses a delegate with a second (int) parameter that is called with the index of the items from the sequence :
DateList
.Select((dateTime, idx) => new {dateTime, idx})
.GroupBy(x => x.dateTime.Date.Subtract(firstDay).Days / 7 + 1)
...and persist the value through the linq chain
.SelectMany(gx => gx, (gx, x) => new {Week = gx.Key,
DateTime = x.dateTime,
Count = gx.Count(),
x.idx})
...then use it to re-order the output
.OrderBy(x => x.idx)
...and strip it from your final selection
.Select(x => new {x.Week, x.DateTime, x.Count});
then you can maintain the same order as the original list.
Solution of #spender is good, but can it be done without OrderBy? It can, because we can use the index for direct indexing into array, but it would not be one linq query:
var resultsTmp =
DateList.Select((d, i) => new { d, i })
.GroupBy(x => x.d.Date.Subtract(firstDay).Days / 7 + 1)
.SelectMany(gx => gx, (gx, x) => new { Week = gx.Key, DateTime = x.d, Count = gx.Count(), x.i })
.ToArray();
var resultsTmp2 = resultsTmp.ToArray();
foreach (var r in resultsTmp) { resultsTmp2[r.i] = r; };
var results = resultsTmp2.Select(r => new { r.Week, r.DateTime, r.Count });
It looks a bit complex. I would probably do something more straightforward like:
var DateList2 = DateList.Select(d => new { DateTime = d, Week = d.Subtract(firstDay).Days / 7 + 1 }).ToArray();
var weeks = DateList2.GroupBy(d => d.Week).ToDictionary(k => k.Key, v => v.Count());
var results = DateList2.Select(d2 => new { d2.Week, d2.DateTime, Count = weeks[d2.Week] });

Groupby and selectMany and orderby doesn't bring back the data I need

I have two List row1 and row2.This is data for row1:
and data for row2:
I Concatenate these two lists into one :
var rows = rows1.Concat(rows2).ToList();
The result would be this:
and then want to groupBy on a few fields and order by with other fields.and do some changes to some data. This is my Code
var results = rows.GroupBy(row => new { row.FromBayPanel, row.TagNo })
.SelectMany(g => g.OrderBy(row => row.RowNo)
.Select((x, i) =>
new
{
TagGroup = x.TagGroup,
RowNo = (i == 0) ? (j++).ToString() : "",
TagNo = (i == 0) ? x.TagNo.ToString() : "",
FromBayPanel = x.FromBayPanel,
totalItem = x.totalItem
}).ToList());
which brings me back this result:
This is not what I really want I want to have this result. I Want all data with same "FromBayPanel" be listed together.
which part of my code is wrong?
I think when you want to order the elements within your group you have to use a different approach as SelectMany will simply flatten your grouped items into one single list. Thus instead of rows.GroupBy(row => new { row.FromBayPanel, row.TagNo }).SelectMany(g => g.OrderBy(row => row.RowNo) you may use this:
rows.OrderBy(x => x.FromBayPanel).ThenBy(x => x.TagNo) // this preserves the actual group-condition
.ThenBy(x => x.RowNo) // here you order the items of every item within the group by its RowNo
.GroupBy(row => new { row.FromBayPanel, row.TagNo })
.Select(...)
EDIT: You have to make your select WITHIN every group, not afterwards:
rows.GroupBy(row => new { row.FromBayPanel, row.TagNo })
.ToDictionary(x => x.Key,
x => x.OrderBy(y => y.RowNo)
.Select((y, i) =>
new
{
TagGroup = y.TagGroup,
RowNo = (i == 0) ? (j++).ToString() : "",
TagNo = (i == 0) ? y.TagNo.ToString() : "",
FromBayPanel = x.FromBayPanel,
totalItem = y.totalItem
})
)
EDIT: Test see here

create n lists of list linq

I have a simple list
var list =
AppUtils.db.GetDataTable("dbo.RankSelectChart", view) // stopred procedure and getting datatable
.AsEnumerable()
.Select(i => new
{
Date = i.Field<DateTime>("lastDatetime"),
P1 = i.Field<decimal>("p1"),
P2 = i.Field<decimal>("P2"),
P3..... P(n)
}
)
.ToList()
.OrderBy(x => x.Date);
than i want to get a list of lists or dictionary like List<Dictionary<Datetime, Decimal>> means Dictionary<Date, P1> .... Dictionary<Date, P(n)>
how to write algorithm which is not depend how many P we have
As it stands, you will need to use reflection to access the properties:
var result = new[]{"P1", "P2", "P3", ...}.Select(p => list.ToDictionary(
i => i.Date,
i => i.GetType().GetProperty(p).GetValue(i)));
However, if you could avoid creating your list in the first place and just pull from the data table directly, it may be easier.
var dt = AppUtils.db.GetDataTable("dbo.RankSelectChart", view); // stopred procedure and getting datatable
var pColumns = dt.Columns.Cast<DataColumn>()
.Where(c => c.ColumnName.StartsWith("p"));
var result = pColumns
.Select(p => dt.AsEnumerable().ToDictionary(
i => i.Field<DateTime>("lastDatetime"),
i => i.Field<DateTime>(p.ColumnName)))
.ToList();
If 'Date' is unique for all records in 'list', then you can use reflection to get the P(i) value for a record in list. Like so:
// build sample data
var list = Enumerable.Range(0, 10)
.ToList()
.Select(x => new {
Date = DateTime.Now.AddMinutes(x),
P1 = new Decimal(x),
P2 = new Decimal(x + 1),
P3 = new Decimal(x + 2)
})
.ToList();
// list partionned by date; assumes that Date is unique in list
List<Dictionary<DateTime, Decimal>> partitionedList;
if (list.Count == 0) {
partitionedList = new List<Dictionary<DateTime, Decimal>>();
} else {
var n = 3;
var listElementType = list[0].GetType();
partitionedList = Enumerable.Range(1, n)
.Select(x => {
var prop = listElementType.GetProperty("P" + x);
var pList = list.ToDictionary(
ll => ll.Date,
ll => (Decimal)prop.GetValue(ll));
return pList;
})
.ToList();
}
If 'Date' is not unique, then it cannot be the key to a dictionary and the desired data structure is not achievable.

LINQ - Select min count

I have a list of strings which contain X in them. I want to select list(s) with the minimum count of X in them. For example:
CountMin("AXBXX", "AAX") will return AAX.
How can I write this qith LINQ in a concise way ?
public static string CountMin(IList<string> inputList)
{
if (inputList == null || !inputList.Any()) return null;
var result = inputList.Select(s => new
{
Item = s,
Count => s.Count(ch => ch == 'X')
})
.OrderBy(item => item.Count).First().Item;
}
Snippet assumes that all elements on list are different to null. If you need it, it could be easily improved.
You can also omit temporary class:
inputList.OrderBy(s => s.Count(c => c == 'X')).First();
string[] list = {"AXBXX", "AAX", "AXX"};
string result = (from word in list
select new { word, wordLen = (word.Length - (word.Replace("X", "")).Length) })
.OrderBy(x => x.wordLen).First().word;
MessageBox.Show(result);
Here's an answer that will get you all of the minimum X strings from the list.
var listOfStrings = new List<string>()
{
"AXB",
"ABXXC",
"ABX",
};
var minimumXs =
listOfStrings
.GroupBy(x => x.Count(y => y == 'X'))
.OrderBy(x => x.Key)
.Take(1)
.SelectMany(x => x);
That gives me:
AXB
ABX

Converting SQL to Linq with groupby, sum and count

I would like to do a group by and on that a sum and a count. I don't seem to be able to create the solution in linq. How can I convert my query to linq?
SELECT HistoricalBillingProductGroup,
COUNT(*),
BillingPeriod,
SUM(TotalMonthlyChargesOtcAndMrc)
FROM [x].[dbo].[tblReport]
group by BillingPeriod, HistoricalBillingProductGroup
order by BillingPeriod
This is what I got sofar in Linq
var result =
context.Reports.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.Select(x => new StatisticsReportLine
{
HistoricalBillingGroup = x.FirstOrDefault().HistoricalBillingProductGroup,
BillingPeriod = x.FirstOrDefault().BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
})
.ToString();
The query I get from this is enormous and takes a very long time to load. In SQL its a matter of milliseconds. I hardly doubt this is the solution.
I believe the calls to x.FirstOrDefault() are the source of your problem. Each one of these will result in a very costly inner query inside the SELECT clause of the generated SQL.
Try using the Key property of the IGrouping<T> instead :
var result = context.Reports
.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.OrderBy(x => x.Key.BillingPeriod)
.Select(x => new StatisticsReportLine
{
HistoricalBillingProductGroup = x.Key.HistoricalBillingProductGroup,
BillingPeriod = x.Key.BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
});
Or if you prefer query syntax:
var result =
(from r in context.Reports
group r by new { r.BillingPeriod, r.HistoricalBillingProductGroup } into g
orderby g.Key.BillingPeriod
select new StatisticsReportLine
{
HistoricalBillingProductGroup = g.Key.HistoricalBillingProductGroup,
BillingPeriod = g.Key.BillingPeriod,
CountOfRows = g.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
});
You could try this one:
var result = context.Reports
.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.Select(x => new StatisticsReportLine
{
HistoricalBillingGroup = x.Key.HistoricalBillingProductGroup,
BillingPeriod = x.Key.BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
}).ToString();
In the above query you make a group by on two properties, BillingPeriod and HistoricalBillingProductGroup. So in each group that will be created, you will have a key, that will be consisted by these two properties.

Categories

Resources