Checking If Intervals Are of Equal Length in a List - c#

I have a List<foo> that has two properties:
start_time and end_time
Assume that we have 100 records in that list. How can I check if all intervals are of equal length? In other terms, I'd like to know if the values of the difference between end and start times for all foo objects are equal.
Where (value = end_time-start_time).
Is it possible to achieve this in a single LINQ line?
Thanks, appreciate it.

Sure, you can write something like this:
var list = new List<foo>();
var areAllEqual = list.GroupBy(l => (l.end_time - l.start_time)).Count() == 1;
Alternatively, if you want to do more with that information:
var differences = list.GroupBy(l => (l.end_time - l.start_time)).ToList();
var numDifferences = differences.Count();
var areAllEqual = numDifferences == 1;
var firstDifference = differences.First().Key;
var allDifferences = differences.Select(g => g.Key);

Something like this should work.
var first = items.First;
var duration = first.end_time - first.start_time;
var allEqual = items.All(i => duration == (i.end_time - i.start_time))

Related

How do I convert this looped code to a single LINQ implementation?

I am trying to optimise the code below which loops through objects one by one and does a database lookup. I want to make a LINQ statement that will do the same task in one transaction.
This is my inefficient looped code;
IStoreUnitOfWork uow = StoreRepository.UnitOfWorkSource.GetUnitOfWorkFactory().CreateUnitOfWork();
var localRunners = new List<Runners>();
foreach(var remoteRunner in m.Runners) {
var localRunner = uow.CacheMarketRunners.Where(x => x.SelectionId == remoteRunner.SelectionId && x.MarketId == m.MarketId).FirstOrDefault();
localRunners.Add(localRunner);
}
This is my very feable attempt at a single query to do the same thing. Well it's not even an attempt. I don't know where to start. The remoteRunners object has a composite key.
IStoreUnitOfWork uow = StoreRepository.UnitOfWorkSource.GetUnitOfWorkFactory().CreateUnitOfWork();
var localRunners = new List<Runners>();
var localRunners = uow.CacheMarketRunners.Where(x =>
x.SelectionId in remoteRunners.SelectionId &&
x.MarketId in remoteRunners.MarketId);
Thank you for looking
So you have an object m, which has a property MarketId. Object m also has a sequence of Runners, where every Runner has a property SelectionId.
Your database has CacheMarketRunners. Every CacheMarketRunner has a MarketId and a SelectionId.
Your query should return allCacheMarketRunners with a MarketId equal to m.MarketId and a SelectionId that is contained in the sequence m.Runners.SelectionId.
If your m does not have too many Runners, say less then 250, consider using Queryable.Contains
var requestedSelectionIds = m.Runners.Select(runner => runner.SelectionId);
var result = CacheMarketRunners.Where(cacheMarketRunner =>
cacheMarketRunner.MarketId == m.MarketId
&& requestedSelectionIds.Contains(cacheMarketRunner.SelectionId));
To improve performance, you need caching transaction results:
var marketRunners = uow.CacheMarketRunners.Where(x => x.MarketId == m.MarketId).ToList();
Transaction results regarding uow are stored in the List, such that you don't have transaction in the for loop. Hence performance should be improved:
var localRunners = new List<Runners>();
foreach(var remoteRunner in m.Runners) {
var localRunner = marketRunners.FirstOrDefault(x => x.SelectionId == remoteRunner.SelectionId);
localRunners.Add(localRunner);
}
You can even remove the for loop:
var localRunners = m.Runners.Select(remoteRunner => marketRunners.FirstOrDefault(x => x.SelectionId == remoteRunner.SelectionId)).ToList();

Slow LINQ missing from list query

I have a pretty standard block of code that compares two lists and returns the items from the first list that are not matched in the second list. (unmatched query)
But when both the lists are large-ish, the unmatched query takes 3 minutes to execute.
// names.Count ~ 91k
var names = xxxxx.ToList();
// namePhonetics.Count ~ 91k
var namePhonetics = yyyyy.ToList();
// this line takes 3 minutes to run
var namesMissingPhonetics = names.Where(n => !namePhonetics.Any(np => np.NameId == n.Id)).ToList();
What can I do to increase the performance of this?
Try this:
var namePhoneticsDict = yyyyy.ToDictionary(x => x.NameId, x => x);
var namesMissingPhonetics = names.Where(n => !namePhoneticsDict.ContainsKey(n.Id)).ToList();

LINQ Filtering - Optimization

I make one database trip to get a list of entities.
I then would like to separate this list into 2 lists, one for the entities that have not expired (using a start and end) which i call TopListings and another which are regular listings, those that have expired or have start/end date as null (the ones that are not TopListings)
I am not entirely sure which filtering is fasted to separate into 2 lists, should I get the toplist first, then filter second list based on what is NOT in the top list for second?
var listings = ListingAdapter.GetMapListings(criteria);
var topListings = listings.Where(x => x.TopStartDate >= DateTime.Now && x.TopExpireDate >= DateTime.Now);
//I AM NOT SURE WHAT THIS LINE SHOULD BE
var regularListings = listings.Where(x => x.TopStartDate < DateTime.Now || x.TopExpireDate < DateTime.Now || x.TopStartDate == null || x.TopExpireDate == null );
Thank you
You might want to use a LookUp
like this:
var lookup = listings.ToLookup(x => x.TopStartDate >= DateTime.Now && x.TopExpireDate >= DateTime.Now);
var topListings = lookup[true];
var regularListings = lookup[false]; // I assume everything not a topListing is a regular listing.
If this isnt enough, you could create an enum
enum ListingType { Top, Regular, WhatEver };
...
var lookup = listings.ToLookUp(determineListingType); // pass a methoddelegate that determines the listingtype for an element.
...
var topListings = lookup[ListingType.Top];
var regularListings = lookup[ListingType.Regular];
var whateverListings = lookup[ListingType.WhatEver];
In this case, it would probably be easier to use a loop, instead of Linq operators:
var topListings = new List<Listing>();
var regularListings = new List<Listing>();
foreach (var x in listings)
{
if (x.TopStartDate >= DateTime.Now && x.TopExpireDate >= DateTime.Now)
topListings.Add(x);
else
regularListings.Add(x);
}
This is also more efficient, because the list is enumerated only once.
Take a look at the 'Except' operator to make things a little easier. You might have to add a .ToList() on topListings first though.
var regularListings = listings.Except(topListings);
http://blogs.msdn.com/b/charlie/archive/2008/07/12/the-linq-set-operators.aspx
Make use of regular foreach loop that's straight forward. You can iterate through listing with one go and add items to appropriate collections. If you are LINQ kind of guy, ForEach extension is what you are looking for:
var topListings = new List<Listing>();
var regularListings = new List<Listing>();
listing.ForEach(item=>{
if (x.TopStartDate < DateTime.Now
|| // I've inverted the condition, since it is faster-one or two conditions will be checked, instead of always two
x.TopExpireDate < DateTime.Now)
regularListings.Add(x);
else
topListings.Add(x);
});

Linq query - returning a sum

I am having trouble figuring out how to do something like the following. This is purely pseudocode:
decimal totalActiveCost = (from i in _context.KeyActives
where i.Pk in (active1fk, active2fk, active3fk, active4fk, active5fk, keyActiveFk)
select sum(i.Cost)...`
Then summing the i.Cost. So basically, I need to return the i.Cost for each "Active" - so, for example, say active1fk is 1, active2fk is 2, and so on. I need to get the Cost for each of these and sum them up.
You can have your active foreign keys in a List<T> like:
List<int> activeFks = new List<int> {1,2,3,4,5,};
var sum = (from i in _context.KeyActives
where activeFks.Contains(i.PK)
select i.Cost).Sum();
Or with a method syntax:
var sum = _context.KeyActives
.Where(r=> activeFks.Contains(r.PK))
.Sum(r=> r.Cost);
Something like this will work:
List<Int> ids = new List<int>();
ids.Add(1);
ids.Add(2);
var result = _context.KeyActives.
Where(c => ids.Contains(c.id))
.Sum(c => c.Cost);
var ids = new List<int> {active1fk, active2fk, active3fk, active4fk, active5fk, keyActiveFk};
var sum = (from i in _context.KeyActives
where ids.Contains(i.Pk)
select i).Sum(a=> a.Cost);

Linq to Objects ordering by arbitrary number of parameters

I have a list of Func defining an ordering:
var ordering = new List<Func<Person, IComparable>>
{ x => x.Surname, x => x.FirstName };
I can order the results with something like...
people = people.OrderBy(ordering[0]).ThenBy(ordering[1]);
I'm trying to figure how to do the above when the list can contain any number of sequential orderings. Is it possible?
people = people.OrderBy(ordering[0]).ThenBy(ordering[1]).ThenBy(ordering[2]);
is the same as
var orderedPeople = people.OrderBy(ordering[0]);
orderedPeople = orderedPeople.ThenBy(ordering[1]);
orderedPeople = orderedPeople.ThenBy(ordering[2]);
people = orderedPeople;
so you simply write a loop like this:
if (ordering.Count != 0)
{
var orderedPeople = people.OrderBy(ordering[0]);
for (int i = 1; i < ordering.Count; i++)
{
orderedPeople = orderedPeople.ThenBy(ordering[i]);
}
people = orderedPeople;
}
As others have mentioned, you can use a loop to do this.
If you prefer, you can also use the Aggregate operator:
// Requires a non-empty ordering sequence.
var result2 = ordering.Skip(1)
.Aggregate(people.OrderBy(ordering.First()), Enumerable.ThenBy);
(or)
// Shorter and more "symmetric" but potentially more inefficient.
// x => true should work because OrderBy is a stable sort.
var result = ordering.Aggregate(people.OrderBy(x => true), Enumerable.ThenBy);
You should be able to do something similar to this
people = people.OrderBy(ordering[0])
foreach(var order in ordering.Skip(1))
{
people = people.ThenBy(order);
}
Alternately
for(i = 0; i < ordering.Count; i++)
{
people = i == 0 ? people.OrderBy(ordering[i]) : people.ThenBy(ordering[i]);
}
Remember that LINQ execution is deferred. You can build up the expression sequentially before accessing the results, doing something like:
var ordered = unordered.OrderBy(ordering.First());
foreach (var orderingItem in ordering.Skip(1))
{
ordered = ordered.ThenBy(orderingItem);
}
You might want to do this with dynamically building up you're expression. More info here: Dynamic LINQ and Dynamic Lambda expressions?

Categories