I have a list which contains instanceNumber properties of type int I want to add leading 0 if its value is less than 10. i.e 01,02...09 after that 10,11,12 and goes on etc. I tried following code but it did not work
var sidList = _sidRepository.GetAllList().Where(q=>q.IsDeleted==false).OrderByDescending(q=>q.Id).ToList();
if (sidList.Count > 0)
{
sidList.Where(w => w.InstanceNumber<10).ToList().
ForEach(s => s.InstanceNumber = s.InstanceNumber.Value.ToString("D").Length + 2);
}
Try this:
var sidList = _sidRepository.GetAllList()
.Where(q => !q.IsDeleted)
.OrderByDescending(q => q.Id)
.ToList();
if (sidList.Any())
{
sidList
.Where(w => w.InstanceNumber < 10)
.ToList()
.ForEach(s => s.InstanceNumber = s.InstanceNumber.Value.ToString("00").Length + 2);
}
What I would suggest:
var sidList = _sidRepository.GetAllList()
.Where(q => !q.IsDeleted)
.OrderByDescending(q => q.Id);
if (sidList.Any())
foreach (var item in sidList.Where(i => i.InstanceNumber < 10))
item.InstanceNumber = item.InstanceNumber.Value.ToString("00").Length + 2;
My suggestion will return a IEnumerable<item> instead of a List<item>, but you can handle it afterwards with a .ToList() if you need it, but you'll benefit from performance, because you'll avoid ToList(ing) two times.
Related
if (model.ConnectedToOtherProfilesId != 0)
{
var fooGroup = fans.GroupBy(x => x.FanId)
.Where(x => x.Any(z => z.ProfileId == model.ConnectedToOtherProfilesId));
var fooGroup2 = fooGroup.Where(grp => grp.Count() > 1);
}
What I need is to put the results from fooGroup2 [IQueryable<IGrouping<int,PF>] into fans which is IQueryiable<PF>
Something like this:
fans = fooGroup2;
You could use a SelectMany.
//IQueryable<PF>
var fooGroup2 = fooGroup.Where(grp => grp.Count() > 1)
.SelectMany(pf => pf);
So I have this function:
var ordersInLast7Days = lineItems
.Where(x => x.OrderLogged > DateTime.Now.AddDays(-7))
.ToList();
ordersInLast7Days.ForEach(lineItem =>
{
var qty = lineItem.Quantity;
var pack = packs.FirstOrDefault(x => x.Id.Equals(lineItem.PackId));
if (pack != null)
{
orderTotalsInLast7Days += qty * pack.Price;
}
});
How would I make that into an Aggregate LINQ function that collects qty * pack.Price?
To elaborate somewhat, I have 3 of these functions that are all the same, so just guna have one method to apply to all Aggregates.
I agree with dasblinkenlight but to provide a solution using aggregate:
var total = lineItems.Where(x => x.OrderLogged > DateTime.Now.AddDays(-7) && packs.Any(y => y.Id.Equals(x.PackId)))
.Aggregate(0, (res, item) => res += item.Quantity * packs.First(y => y.Id.Equals(item.PackId)).Price);
You can use Sum to accumulate the total of qty * pack.Price, like this:
orderTotalsInLast7Days = ordersInLast7Days
.Select(lineItem => new {
qty = lineItem.Quantity
, pack = packs.FirstOrDefault(x => x.Id.Equals(lineItem.PackId))
})
.Where(p => p.pack != null)
.Sum(p => p.qty * p.pack.Price);
This is a straightforward translation of your iterative code, which uses an anonymous type instead of local variables.
You could do it this way:
orderTotalsInLast7Days =
(
from lineItem in lineItems
where lineItem.OrderLogged > DateTime.Now.AddDays(-7)
let qty = lineItem.Quantity
from pack in packs.Where(x => x.Id.Equals(lineItem.PackId)).Take(1)
select qty * pack.Price
).Sum();
I have a IList<string>() which holds some string values, and there could be duplicated items in the list. What I want is to append a index number to end of the string to eliminate the duplication.
For example, I have these values in my list: StringA, StringB, StringC, StringA, StringA, StringB. And I want the result looks like: StringA1, StringB1, StringC, StringA2, StringA3, StringB2. I need to retain the original order in list.
Is there a way I can just use one Lambda expression?
You are looking for something like this:
yourList.GroupBy(x => x)
.SelectMany(g => g.Select((x,idx) => g.Count() == 1 ? x : x + idx))
.ToList();
Edit: If the element order matters, here is another solution:
var counts = yourList.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());
var values = counts.ToDictionary(x => x.Key, x => 0);
var list = yourList.Select(x => counts[x] > 1 ? x + ++values[x] : x).ToList();
You can do:
List<string> list = new List<string> { "StringA", "StringB", "StringC", "StringA", "StringA", "StringB" };
var newList =
list.Select((r, i) => new { Value = r, Index = i })
.GroupBy(r => r.Value)
.Select(grp => grp.Count() > 1 ?
grp.Select((subItem, i) => new
{
Value = subItem.Value + (i + 1),
OriginalIndex = subItem.Index
})
: grp.Select(subItem => new
{
Value = subItem.Value,
OriginalIndex = subItem.Index
}))
.SelectMany(r => r)
.OrderBy(r => r.OriginalIndex)
.Select(r => r.Value)
.ToList();
and you will get:
StringA1,StringB1,StringC,StringA2,StringA3,StringB2
If you don't want to preserve order then you can do:
var newList = list.GroupBy(r => r)
.Select(grp => grp.Count() > 1 ?
grp.Select((subItem, i) => subItem + (i + 1))
: grp.Select(subItem => subItem))
.SelectMany(r => r)
.ToList();
This uses some lambda expressions and linq to do it, maintaining the order but I'd suggested a function with a foreach loop and yield return would be better.
var result = list.Aggregate(
new List<KeyValuePair<string, int>>(),
(cache, s) =>
{
var last = cache.Reverse().FirstOrDefault(p => p.Key == s);
if (last == null)
{
cache.Add(new KeyValuePair<string, int>(s, 0));
}
else
{
if (last.Value = 0)
{
last.Value = 1;
}
cache.Add(new KeyValuePair<string, int>(s, last.Value + 1));
}
return cache;
},
cache => cache.Select(p => p.Value == 0 ?
p.Key :
p.Key + p.Value.ToString()));
Is there any way to avoid "The result of a query cannot be enumerated more than once" exception without using ToList()?
Here is a simplified version of my code:
var entities = _db.Trades.Where(t => t.A > 10);
int totalCount = entities.Count();
entities = entities.Where(t => t.B > 10);
int totalCountAfterAdditionalFilter = entities.Count();
I cannot call ToList() due to performance considerations. I know that I could just generate one more IQueryable, but that seems wrong (I have more filters like this). Could I somehow preserve/duplicate the IQueryable after my first call of Count()?
Thanks!
No, you can't achieve your desired result like that. As an alternative you can, however, save your filters to variables and then compose them as needed:
Func<Trade, bool> filter1 = t => t.A > 10;
Func<Trade, bool> filter2 = t => t => t.B > 10;
Func<Trade, bool> compositeFilter = t => filter1(t) && filter2(t);
int totalCount = _db.Trades.Count(filter1);
int totalCountAfterAdditionalFilter = _db.Trades.Count(compositeFilter);
//Need more?
compositeFilter = t => compositeFilter(t) && t.C > 100;
int totalAfterMoreFilters = _db.Trades.Count(compositeFilter);
may be:
Trades.Where(x => x.A > 10).Select(x => new { i = 1, j = x.B > 10 ? 1 : 0}).
GroupBy(y => y.i).
Select(g => new { c = g.Count(), = g.Sum(z => z.j)})
That's give you the 2 informations in one query.
I have a list List<UserRoles> roles that has this structure
{r:1,u:1,v:3},
{r:1,u:1,v:5},
{r:2,u:1,v:9},
{r:3,u:2,v:10}
I am trying to write a LINQ statement that will filter out only the "r"s that have values 1 & 2 and return a collection of ints/strings of "v"s
This is what I am trying to do and my problem is in the part where I want to transform the into that holds only the corresponding "v"s.
List<Int32> = roles.Where(r => r.r == 1 || r.r == 2)
.Select(i => new Int32{id = i.v});
This doesn't compile with an error that 'id' is unknown.
the end result that I need is this:
List<Int32>
{v:3},
{v:5},
{v:9}
Sound like you need a list of int:
List<int> result = roles.Where(r => r.r == 1 || r.r == 2)
.Select(i => i.v)
.ToList();
In case you have a list of int to filter, you can use Contains method to avoid lots of ||:
var filters = new[] { 1, 2};
List<int> result = roles.Where(r => filters.Contains(r.r))
.Select(i => i.v)
.ToList();
Or maybe you need {v:9}, you can use anonymous type with var keyword:
var result = roles.Where(r => filters.Contains(r.r))
.Select(i => new { i.v })
.ToList();
I guess v is already an int.
So the solution would be as simple as :
var result = roles.Where(r => r.r == 1 || r.r == 2).Select(i => i.v).ToList();
If what you want is an array of anonymous objects, use this:
var res = roles.Where(r => r.r == 1 || r.r == 2).Select(i => new{i.v}).ToList();
This would produce a list of objects with a single property called v.
If you are looking for a list of integers, and v is an int in the original class, use this:
var res = roles.Where(r => r.r == 1 || r.r == 2).Select(i => i.v ).ToList();
// note that there's no new here ^^^^^
You've used an annoymous type but then added Int32 in front of it which is illegal.
List<Int32> results = roles.Where(r => r.r == 1 || r.r == 2)
.Select(i => new { i.v }).ToList();