Building LINQ Dynamic Order Clause, But Cast Field - linq

The following code works great of I want to dynamically build an orderby:
public static IQueryable<TEntity> OrderByAnyField<TEntity>(this IQueryable<TEntity> source, string orderByProperty, bool desc, Type propertyType)
{
string command = desc ? "OrderByDescending" : "OrderBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote(orderByExpression));
return source.Provider.CreateQuery<TEntity>(resultExpression);
}
So, I want to be able to change the CAST of the sort. So, as an example, I would like to take:
.OrderBy(x => x.Something)
and do this instead:
.OrderBy(x => double.Parse(x.Something))
Any help is greatly appreciated

I am sharing one simpler approach to do the same. You can add generics as per your requirement. You can play on data any way you want
static object GetOrder(Table tb, string propertyName, bool desc)
{
if (desc)
return 0;
PropertyInfo pI = typeof(Table).GetProperty(propertyName);
var val = pI.GetValue(tb);
return val;
}
static object GetOrderDesc(Table tb, string propertyName, bool desc)
{
if (!desc)
return 0;
PropertyInfo pI = typeof(Table).GetProperty(propertyName);
var val = pI.GetValue(tb);
return val;
}
static void Main(string[] args)
{
bool desc = false;
List<Table> table = new List<Table>() {
new Table() { ID = "03", X = "Str1", Y = "C1", P = 10 },
new Table() { ID = "04", X = "Str1", Y = "C1", P = 5 },
new Table() { ID = "05", X = "Str1", Y = "C1", P = 1 },
new Table() { ID = "06", X = "Str1", Y = "C1", P = 2 },
new Table() { ID = "07", X = "Str2", Y = "C1", P = 25 },
new Table() { ID = "08", X = "Str2", Y = "C1", P = 4 },
new Table() { ID = "09", X = "Str1", Y = "C2", P = 411 },
new Table() { ID = "10", X = "Str1", Y = "C2", P = 2356 },
new Table() { ID = "11", X = "Str2", Y = "C2", P = 12 },
new Table() { ID = "12", X = "Str2", Y = "C2", P = 33 },
};
var sortedTable = table.OrderBy(x => GetOrder(x, "P", desc)).OrderByDescending(x => GetOrderDesc(x, "P", desc));
}

Related

DataTable distinct rows by max value

I need distinct values only by X and Y but with ID field and row with max value of P
For example here is my DataTable
ID X Y P
03 Str1 C1 10
04 Str1 C1 5
05 Str1 C1 1
06 Str1 C1 2
07 Str2 C1 25
08 Str2 C1 4
09 Str1 C2 411
10 Str1 C2 2356
11 Str2 C2 12
12 Str2 C2 33
Result for above DataTable should be following.
ID X Y P
03 Str1 C1 10
07 Str2 C1 25
10 Str1 C2 2356
12 Str2 C2 33
public class Table
{
public string ID { get; set; }
public string X { get; set; }
public string Y { get; set; }
public int P { get; set; }
}
List<Table> table = new List<Table>() {
new Table() { ID = "03", X = "Str1", Y = "C1", P = 10 },
new Table() { ID = "04", X = "Str1", Y = "C1", P = 5 },
new Table() { ID = "05", X = "Str1", Y = "C1", P = 1 },
new Table() { ID = "06", X = "Str1", Y = "C1", P = 2 },
new Table() { ID = "07", X = "Str2", Y = "C1", P = 25 },
new Table() { ID = "08", X = "Str2", Y = "C1", P = 4 },
new Table() { ID = "09", X = "Str1", Y = "C2", P = 411 },
new Table() { ID = "10", X = "Str1", Y = "C2", P = 2356 },
new Table() { ID = "11", X = "Str2", Y = "C2", P = 12 },
new Table() { ID = "12", X = "Str2", Y = "C2", P = 33 },
};
var ret = table.GroupBy(p => new { p.X, p.Y }).Select(i => new { Table = new Table() { X = i.Key.X, Y = i.Key.Y, P = i.Max(o => o.P) }, Items = i.Select(f => f) }).ToList();
ret.ForEach(c => c.Table.ID = c.Items.First(i => i.P == c.Table.P).ID);
var finalResult = ret.Select(x => x.Table).ToList();
dt.AsEnumerable().OrderBy(row => row["X"]).ThenByDescending(row => row["Y"]).GroupBy(row => new { a = row["X"], b = row["Y"] }).Select(group => group.First()).CopyToDataTable();

LINQ - Group By child property

I have a list of users, each user has string array property called Tags. I am trying to get a unique list of tags and a total count, any idea what I a missing here? I am using LinqPad to write my test query, please see the example code:
void Main()
{
List<User> users = new List<User>(){
new User {Id = 1, Tags = new string[]{"tag1", "tag2"}},
new User {Id = 2, Tags = new string[]{"tag3", "tag7"}},
new User {Id = 3, Tags = new string[]{"tag7", "tag8"}},
new User {Id = 4, Tags = new string[]{"tag1", "tag4"}},
new User {Id = 5 },
};
var uniqueTags = users.Where(m=>m.Tags != null).GroupBy(m=>m.Tags).Select(m=> new{TagName = m.Key, Count = m.Count()});
uniqueTags.Dump();
// RESULT should BE:
// tag1 - Count(2)
// tag2 - Count(1)
// tag3 - Count(1)
// tag4 - Count(1)
// tag7 - Count(2)
// tag8 - Count(1)
}
public class User{
public int Id {get;set;}
public string[] Tags {get;set;}
}
You can flatten to IEnumerable<string> before grouping:
var uniqueTags = users.SelectMany(u => u.Tags ?? new string[0])
.GroupBy(t => t)
.Select(g => new { TagName = g.Key, Count = g.Count() } );
LINQPad C# Expression version:
new[] {
new { Id = 1, Tags = new[] { "tag1", "tag2" } },
new { Id = 2, Tags = new[] { "tag3", "tag7" } },
new { Id = 3, Tags = new[] { "tag7", "tag8" } },
new { Id = 4, Tags = new[] { "tag1", "tag4" } },
new { Id = 5, Tags = (string[])null }
}
.SelectMany(u => u.Tags ?? Enumerable.Empty<string>())
.GroupBy(t => t)
.Select(g => new { TagName = g.Key, Count = g.Count() } )

Updating Collection from other collection for matching items

I have two collections as mentioned below. I have update two properties of "trade" from the other collection "refData" if those values exists in "refData".
Model:
class Trade
{
public int Id { get; set; }
public string PayIndex { get; set; }
public string RecIndex { get; set; }
public string PayCurrency { get; set; }
public string RecCurrency { get; set; }
}
class RefData
{
public string IndexLabel { get; set; }
public string Symbol { get; set; }
}
Sample Date:
var refData = new List<RefData>
{
new RefData { IndexLabel = "A1", Symbol="ABC1"},
new RefData { IndexLabel = "A2", Symbol="ABC2"},
new RefData { IndexLabel = "B1", Symbol="BCD1"},
new RefData { IndexLabel = "B2", Symbol="BCD2"},
};
var trades = new List<Trade>
{
new Trade { Id = 1, PayIndex = "A1", RecIndex = "B1"},
new Trade { Id = 2, PayIndex = "A2", RecIndex = ""},
new Trade { Id = 3, PayIndex = "", RecIndex = "B2"},
new Trade { Id = 4, PayIndex = "A3", RecIndex = "B3"}
};
I want to update PayCurrency and RecCurrency of "trades" with Symbol property of "refData" if trade's PayIndex and RecCurrency exists in "refData".
Output:
var Output = new List<Trade>
{
new Trade { Id = 1, PayIndex = "A1", RecIndex = "B1", PayCurrency = "ABC1", RecCurrency="BCD1"},
new Trade { Id = 2, PayIndex = "A2", RecIndex = "", PayCurrency = "ABC2", RecCurrency=""},
new Trade { Id = 3, PayIndex = "", RecIndex = "B2", PayCurrency = "", RecCurrency="BCD2"},
new Trade { Id = 4, PayIndex = "A3", RecIndex = "B3", PayCurrency = "", RecCurrency=""}
};
For c#6 and above you can do like below
var result = trades.Select(t => new Trade() {
Id= t.Id,
PayIndex = t.PayIndex,
RecIndex = t.RecIndex,
PayCurrency = refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.PayIndex.ToLower()))?.Symbol ?? "",
RecCurrency = refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.RecIndex.ToLower()))?.Symbol ?? ""
}).ToList();
For Older versions
var result = trades.Select(t => new Trade() {
Id= t.Id,
PayIndex = t.PayIndex,
RecIndex = t.RecIndex,
PayCurrency = refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.PayIndex.ToLower())) != null ? refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.PayIndex.ToLower())).Symbol : "",
RecCurrency = refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.RecIndex.ToLower())) != null ? refData.SingleOrDefault(r => r.IndexLabel.ToLower().Equals(t.RecIndex.ToLower())).Symbol : ""
}).ToList();
Here is working example
Update using #SAJ answer
var output = (from r in trades
join p in refData on r.PayIndex equals p.IndexLabel
into g1
from s in g1.DefaultIfEmpty()
join t in refData on r.RecIndex equals t.IndexLabel into g2
from a in g2.DefaultIfEmpty()
select Trade { Id=r.Id,PayIndex=r.PayIndex,RecIndex=r.RecIndex, RecCurrency = a != null ? a.Symbol : "", PayCurrency = s != null ? s.Symbol : ""}).ToList();
You can try this
var output = (from r in trades
join p in refData on r.PayIndex equals p.IndexLabel
into g1
from s in g1.DefaultIfEmpty()
join t in refData on r.RecIndex equals t.IndexLabel into g2
from a in g2.DefaultIfEmpty()
select new { r, RecSymbol = a?.Symbol, PaySymbol = s?.Symbol }).ToList();
output.ForEach(o =>
{
o.r.PayCurrency = o.PaySymbol;
o.r.RecCurrency = o.RecSymbol;
});

Linq Query: Convert Key value pair to generic list of objects

I have following list of objects, it is like property & its value. I need to convert it to generic list of objects.
public class Prop
{
public string Name { get; set; }
public string Value { get; set; }
}
var list = new List<Prop> {
new Prop { Name = "x", Value = "10" },
new Prop { Name = "y", Value = "11" },
new Prop { Name = "z", Value = "12" },
new Prop { Name = "x", Value = "101" },
new Prop { Name = "y", Value = "102" },
new Prop { Name = "z", Value = "103" }
};
Actually, I want to convert it to as shown below
var list2 = new List<xyx> {
new xyx { x = "10", y = "11", z = "12" },
new xyx { x = "101", y = "102", z = "103" }
};
public class xyx
{
public string y { get; set; }
public string x { get; set; }
public string z { get; set; }
public string d { get; set; }
}
Here is a solution done in LINQ. I do not make any claim that it's the most efficient, and I'm not sure LINQ is the best way to do this, but it does get the job done.
I am assuming that the original list comes in groups of 3 (x,y,z), though the order of the grouping does not matter.
var list2 = list
.Select((prop, index) => new { prop, index })
.GroupBy(g => g.index / 3, g => g.prop) //make groups of 3
.Select(g => new xyx {
x = g.First(prop => prop.Name == "x").Value,
y = g.First(prop => prop.Name == "y").Value,
z = g.First(prop => prop.Name == "z").Value
})
.ToList();

LINQ Group By Subtotal & Total

I have a Batch with BatchItems entered by multiple users. I'm trying to not only get the subtotal per user for a single batch, but also grand total for that same batch regardless of the user grouping. Its this last part that I can't figure out. How might I get that total in order to return it as a list?
from b in context.BatchItem
where b.BatchId == batchId
group b by b.CreatedByUser into g
select new
{
BatchName = g.FirstOrDefault<BatchItem>().Batch.Name,
User = g.Key,
UserBatchCount = g.Count<BatchItem>(),
// something like this is what I can't figure out
TotalBatchCount = b.Count<BatchItem>()
}
Not sure, but try this:
from b in context.BatchItem
let cnt = context.BatchItem.Count()
b.BatchId == batchId
group b by b.CreatedByUser into g
select new
{
BatchName = g.FirstOrDefault<BatchItem>().Batch.Name,
User = g.Key,
UserBatchCount = g.Count<BatchItem>(),
// something like this is what I can't figure out
TotalBatchCount = cnt
}
var batch1 = new { Name = "Batch A", BatchId = 1, CreatedByUser = "David" };
var batch2 = new { Name = "Batch A", BatchId = 1, CreatedByUser = "Mike" };
var batch3 = new { Name = "Batch B", BatchId = 2, CreatedByUser = "Cathy" };
var batch4 = new { Name = "Batch B", BatchId = 2, CreatedByUser = "Cathy" };
var batch5 = new { Name = "Batch B", BatchId = 2, CreatedByUser = "David" };
var batch6 = new { Name = "Batch C", BatchId = 3, CreatedByUser = "Henry" };
var batchItem = new[] { batch1, batch2, batch3, batch4, batch5, batch6 }.ToList();
var result =
batchItem.Where(b => b.BatchId == batchId)
.GroupBy(b => b.BatchId, b => b)
.SelectMany(g =>
g.GroupBy(c => c.CreatedByUser, c => c)
.SelectMany(sg =>
sg.Select(c => new
{
BatchName = g.First().Name,
UserName = c.CreatedByUser,
UserBatchCount = sg.Count(),
TotalBatchCount = g.Count()
})
)
);
Audit Log: Removed previous two code blocks.

Resources