check that values in lists match - c#

I have 2 lists as described below
How can i verify that all sitempath values that exist in lstOldItems also exist in lstNewItems
C# Code
List<ItemsUnderControlObject> lstNewItems
List<ItemsUnderControlObject> lstOldItems
public class ItemsUnderControlObject
{
public ItemsUnderControlObject();
public bool bButtonEnabled { get; set; }
public short iChkInterval { get; set; }
public int iItemUnderCtrlUniqueID { get; set; }
public DateTime? ItemCreationDateTime { get; set; }
public DateTime? ItemLastAccessDateTime { get; set; }
public DateTime? ItemLastModifiedDateTime { get; set; }
public long lngItemSize { get; set; }
public string sItemBackupLocation { get; set; }
public string sItemcategory { get; set; }
public string sItemCurrentStatus { get; set; }
public DateTime sItemDatabaseCreationDateTime { get; set; }
public string sItemName { get; set; }
public string sItemPath { get; set; }
public string sItemRequestStatus { get; set; }
public string sItemTask { get; set; }
public string sItemValue { get; set; }
public string sItemValueSHA256 { get; set; }
public string sSystemID { get; set; }
}

Why not use LINQ's Except extension method seen here:
var oldItemPaths = lstOldItems.Select(l => l.sItemPath).Distinct();
var newItemPaths = lstNewItems.Select(l => l.sItemPath).Distinct();
bool isSame = !oldItemPaths.Except(newItemPaths).Any();
Or, using #Magnus' way of doing it with the above code (minus the Except):
bool isSame = oldItemPaths.All(x => newItemPaths.Contains(x));

One liner, in case you don't want to extract the paths to different lists:
stOldItems.All(x => lstNewItems.Any(y=> x.sItemPath == y.sItemPath));

For fast look-up first add the items in lstNewItems to a HashSet, than use All:
var set = new HashSet<string>(lstNewItems.Select(x => x.sItemPath));
var res = lstOldItems.All(x => set.Contains(x.sItemPath));

try linq,
something along the lines of this
List<string> sitempaths = lstNewItems.Select(i => i.sitempath).ToList();
bool hasSitempaths = lstOldItems
.Where(x => sitempaths.contains(x.sitempath)).ToList()
.Count == lstOldItems.Count;
note, this is not actually tested, you might have to adjsut

Related

Is manual foreach loop faster or linq query on collections in the following scenario?

I want to know which approach is faster. I have the following class:
public class AccountBalance
{
public long AccountID { get; set; }
public string AccountNumber { get; set; }
[NotRequiredForDataTable]
public IEnumerable<AccountMediaBalance> AccountMediaBalances { get; set; }
}
public class AccountMediaBalance
{
public long AccountID { get; set; }
public long MediaID { get; set; }
public string MediaSerialNumber { get; set; }
public decimal? CashAmount { get; set; }
public int FareID { get; set; }
public bool ShowID { get; set; }
public bool ShareCash { get; set; }
public bool ShareToken { get; set; }
public bool SharePass { get; set; }
public IEnumerable<Token> Tokens { get; set; }
public IEnumerable<Pass> Passes { get; set; }
}
public class Token
{
public long TokenID { get; set; }
public long AccountID { get; set; }
public long MediaProductID { get; set; }
public long MediaID { get; set; }
public long? ActivateByMediaID { get; set; }
public string SerialNumber { get; set; }
public decimal? TransferValue { get; set; }
public DateTimeOffset CreateTime { get; set; }
public DateTimeOffset? ActivateTime { get; set; }
public DateTimeOffset? ExpiryTime { get; set; }
}
public class Pass
{
public long MediaProductID { get; set; }
public long AccountID { get; set; }
public long MediaID { get; set; }
public int ProductID { get; set; }
public long? ActivateByMediaID { get; set; }
public string SerialNumber { get; set; }
public DateTimeOffset CreateTime { get; set; }
public DateTimeOffset? ActivateTime { get; set; }
public DateTimeOffset? ExpiryTime { get; set; }
}
I have a list of AccountBalance data as List<AccountBAlance> and I want to transform data in a way that I want to separate AccountMediaBalance collection in one list, All tokens in one list and all passes in a separate list.
There are two approaches for doing this:
public void SaveAccountBalances(List<AccountBalance> accountBalances)
{
if (accountBalances != null)
{
var mediaBalances = accountBalances.SelectMany(x => x.AccountMediaBalances ??
Enumerable.Empty<AccountMediaBalance>()).ToList();
var tokens = mediaBalances.SelectMany(x => x.Tokens ?? Enumerable.Empty<Token>()).ToList();
var passes = mediaBalances.SelectMany(x => x.Passes ?? Enumerable.Empty<Pass>()).ToList();
}
}
The other approach would be like following:
public void SaveAccountBalances(List<AccountBalance> accountBalances)
{
var mediaBalances = new List<AccountMediaBalance>();
var tokens = new List<Token>();
var passes = new List<Pass>();
if (accountBalances != null)
{
foreach (var item in accountBalances)
{
mediaBalances.AddRange(item.AccountMediaBalances ?? Enumerable.Empty<AccountMediaBalance>());
}
foreach (var item in mediaBalances)
{
tokens.AddRange(item.Tokens ?? Enumerable.Empty<Token>());
passes.AddRange(item.Passes ?? Enumerable.Empty<Pass>());
}
}
}
Performance is a big concern. Can anyone put me in the right direction and let me know which approach is faster and why?
foreach loop uses GetEnumerator directly, while linq creates the query object first and then GetEnumerator. So it is naturally a little bit faster to use foreach loop for a single iteration but it still makes the code look better to use linq.

c# SelectMany, gather information from a nested model in a list

I am working on a project and I am trying to clean up some code. I can get the information I need using 2 lines, however I am new to using SelectMany and figure maybe I am looking at this wrong. So what I'd like to to take my two lines of code and turn it into 1 line of code if at all possible.
Selecting: I need the BambooDeployModel by a particular name, in the example 'test' is the variable for this.
Then once it narrows down my list to a particular model, I need to select the "Test" environment by name.
Here are my lines as is:
List<BambooDeployModel> deployments
var q = deployments.SelectMany(b => b.environments.Where(f => f.name == "Test"), (b, f) => f).SelectMany(f => deployments.Where(o => o.name == test)).Distinct();
var p = q.SelectMany(b => b.environments).Where(f => f.name == "Test").Distinct();
And here is the model, it is just a generic model based on values received from Bamboo based on deployments in our system.
public class BambooDeployModel
{
public int id { get; set; }
public GenericSetKey key { get; set; }
public string name { get; set; }
public GenericSetKey planKey { get; set; }
public string description { get; set; }
public List<Environment> environments { get; set; }
public Operations operations { get; set; }
}
public class GenericSetKey
{
public KeyValuePair<string, string> key { get; set; }
}
public class Environment
{
public int id { get; set; }
public GenericSetKey key { get; set; }
public string name { get; set; }
public string description { get; set; }
public int deploymentProjectId { get; set; }
public Operations operations { get; set; }
public string position { get; set; }
public string configurationState { get; set; }
}
public class Operations
{
public bool canView { get; set; }
public bool canEdit { get; set; }
public bool canDelete { get; set; }
public bool allowedToExecute { get; set; }
public bool canExecute { get; set; }
public bool allowedToCreateVersion { get; set; }
public bool allowedToSetVersionStatus { get; set; }
}

how to make Value cannot be null, null

Im having a method like this
public List<GSMData> GetGSMList()
{
return meters.Select(x => x.Gsmdata.Last())
.ToList();
}
and i get a "Value cannot be null." exeption. How do i make it so the value can be null?
GSMData object
public class GSMData : Meter
{
public DateTime TimeStamp { get; set; }
public int SignalStrength { get; set; }
public int CellID { get; set; }
public int LocationAC { get; set; }
public int MobileCC { get; set; }
public int MobileNC { get; set; }
public string ModemManufacturer { get; set; }
public string ModemModel { get; set; }
public string ModemFirmware { get; set; }
public string IMEI { get; set; }
public string IMSI { get; set; }
public string ICCID { get; set; }
public string AccessPointName { get; set; }
public int MobileStatus { get; set; }
public int MobileSettings { get; set; }
public string OperatorName { get; set; }
public int GPRSReconnect { get; set; }
public string PAP_Username { get; set; }
public string PAP_Password { get; set; }
public int Uptime { get; set; }
}
you better check for Gsmdata having items or not
public List<GSMData> GetGSMList()
{
return meters.Where(x=>x.Gsmdata!=null && x.Gsmdata.Any()).Select(x => x.Gsmdata.Last())
.ToList();
}
I'm guessing your Gsmdata property is null.
In this case, you could use the Linq .Where() method, to make this:
public List<GSMData> GetGSMList()
{
return meters.Where(x => x.Gsmdata != null)
.Select(x => x.Gsmdata.Last())
.ToList();
}
But you should clarify what exactly is null for better answers.
Try excluding null items by filtering the list immediately, and before doing the select.
public List GetGSMList()
{
return meters.Where(x=> x.Gsmdata != null).Select(x => x.Gsmdata.Last())
.ToList();
}

C# get string from list

I am trying to get a string from a list in c#, but can't find a way to do it. Heres my code
public class CurrentCondition
{
public string cloudcover { get; set; }
public string humidity { get; set; }
public string observation_time { get; set; }
public string precipMM { get; set; }
public string pressure { get; set; }
public string temp_C { get; set; }
public string temp_F { get; set; }
public string visibility { get; set; }
public string weatherCode { get; set; }
public List<WeatherDesc> weatherDesc { get; set; }
public List<WeatherIconUrl> weatherIconUrl { get; set; }
public string winddir16Point { get; set; }
public string winddirDegree { get; set; }
public string windspeedKmph { get; set; }
public string windspeedMiles { get; set; }
}
public class Data
{
public List<CurrentCondition> current_condition { get; set; }
}
and I want to get, for example, the temp_F string from the current_condition list. How can I do this?
Assuming you want all the temperatures from your list of CurrentCondition instances, you could do this easily using Linq:
List<string> temps = current_condition.Select(x => x.temp_F).ToList();
In light of the accepted answer, here's how to get a specific temperature with Linq:
string temp = current_condition.Where(x => x.observation_time == "08:30").FirstOrDefault(x => x.temp_F);
Since current_condition is a list, you would have to know which list index you are interested in. Say you want index 0, you would write
Data data = new Data();
// Some code that populates `current_condition` must somehow run
string result = data.current_condition[0].temp_F.
List<string> list = new List<string>();
current_condition.ForEach(cond => list.Add(cond.temp_F));
You can use ElementAt(int) to access an object in a list.
String t = current_condition.ElementAt(index).temp_F;

Strongly Typed List.GroupBy()

I've been trying to find an answer to this on google and on SO
but everywhere I have found uses anonymously typed result lists
what I am trying to acheive is to take a List<SecondaryStandard>
and create a grouped List of SecondaryStandard
each SecondaryStandard looks like this
public class SecondaryStandard
{
public string Id { get; set; }
public int IdNumeric { get; set; }
public string IdText { get; set; }
public Sample Sample { get; set; }
public string StandardName { get; set; }
public DateTime DateCompleted { get; set; }
public SamplePoint SamplingPoint{ get; set; }
public Instrument Instrument{ get; set; }
public string ContainerId { get; set; }
public double Value { get; set; }
public string ComponentName { get; set; }
public string PointLocation { get; set; }
public string Description { get; set; }
public string Description2 { get; set; }
public string Analysis { get; set; }
public string Units { get; set; }
}
what i want is a List() where the Value Property is an average of results for each ComponentName.
Any ideas on how I could achieve this in a strongly typed way or do I need to suck it up and use anonymous objects to achieve what I'm looking for?
You mean this?
List<SecondaryStandard> list = new List<SecondaryStandard>();
// populate list
List<SecondaryStandard> result = list
.GroupBy(l => l.ComponentName)
.Select(s => new SecondaryStandard() { ComponentName = s.Key, Value = s.Average(x => x.Value) }).ToList();

Categories