Compare two lists on one property and dont add duplicate
Hello so for some reason using various examples i havent been able to solve this.
So i have two lists one containing global values and one vlues that are set on a specific property. What i want to achieve is compare the two lists and keep the specific ones and then add the global ones that are not in the specific list based on its name.
i have tried this
var pidConfigValues = await _database.GetConfigurationValuesForPid(productGroup); var globalConfigValues = await _database.GetGlobalConfigurationValues(); var allConfigs = pidConfigValues.Where(c => globalConfigValues.All(d => c.Name != d.Name)).ToList();
I guess something is wrong with the Where condition because the allConfigs ends up as empty. The both variables that gets compared are lists of same type of object
Example data
pidConfigValues would consist of objects like
Name: config.myConfig, Pid: 2, Value: 1
and globalConfigValues would be like
Name: config.myConfig, Pid: Null, Value: 0 Name: config.someOtherConfig, Pid: Null, Value: 1
So in the example above i would want allConfigs to be
Name: config.myConfig, Pid: 2, Value: 1 Name: config.someOtherConfig, Pid: Null, Value: 1
So in allConfigs only the config.myConfig with pid would be shown and from global only add the ones that does not exist in the specific one
Here is one way of doing it:
var pidConfigValues = new List<Config>() { new Config() { Name = "config.myConfig", Pid = 2, Value = 1} }; var globalConfigValues = new List<Config>() { new Config() { Name = "config.myConfig", Pid = null, Value = 0}, new Config() { Name = "config.someOtherConfig", Pid = null, Value = 1} }; var result = pidConfigValues.Concat(globalConfigValues) .GroupBy(x => x.Name) .Select(x => x.First()) //if multiple entities have the same name pick the first one which will be the one from pidConfigValues
One solution would be to use Union in combination with a custom EqualityComparer that compares the configs based on their Name-property:
// in your code: var allConfigs = pidConfigValues.Union(globalConfigValues, new MyConfigComparer()).ToList(); // sample for the comparer: public class MyConfigComparer : IEqualityComparer<MyConfig> { public bool Equals(MyConfig c1, MyConfig c2) { if (object.ReferenceEquals(c1, c2)) return true; if (c1 == null || c2 == null) return false; return c1.Name.Equals(c2.Name, StringComparison.Ordinal); } public int GetHashCode(MyConfig x) { return x.Name.GetHashCode(); } }
Ciao, you can use Distinct (by rewriting EqualityComparer). Here working example:
namespace ConsoleApplication1 { class Program { static void Main(string[] args) { var pidConfigValues = new List<Configuration>(); var globalConfigValues = new List<Configuration>(); Configuration pidConfigValue = new Configuration("config.myConfig", 2, 1); Configuration globalConfigValue1 = new Configuration("config.myConfig", null, 0); Configuration globalConfigValue2 = new Configuration("config.someOtherConfig", null, 1); globalConfigValues.Add(globalConfigValue1); pidConfigValues.Add(pidConfigValue); globalConfigValues.Add(globalConfigValue2); List<Configuration> result = pidConfigValues.Concat(globalConfigValues) .Distinct(new ConfigurationEqualityComparer()).ToList(); Console.WriteLine(String.Join(",", result)); Console.ReadLine(); } } public class Configuration { public string _name = ""; public Nullable<int> _pid = null; public int _value = -1; public Configuration(string name, Nullable<int> pid, int value) { this._name = name; this._pid = pid; this._value = value; } public override string ToString() { return "Name: " + this._name + " PID:" + this._pid + " Value:" + this._value + Environment.NewLine; } } public class ConfigurationEqualityComparer : EqualityComparer<Configuration> { public override bool Equals(Configuration c1, Configuration c2) { if (c1 == null && c2 == null) return true; else if (c1 == null || c2 == null) return false; else if (c1._name.Equals(c2._name)) { if (c1._pid == null || c2._pid == null) return true; else return false; } else return false; } public override int GetHashCode(Configuration cnf) { int hCode = cnf._value ^ cnf._value; return hCode.GetHashCode(); } } }
Explanation: Concat two lists and get only Distinct values. Equality comparer must be rewrited because we are using objects so we have to define which object is equal to another.
So your case is complicated to be solved by simple union or join operation. But simple enough to be solved by some simple select and concat operations.
What you need is to loop all loaded pidConfigValues and override a specific property with the global configuration, and then create a collection containing all unique configurations. Is that correct?
If so the solution could be like this:
var pidConfigValues = await _database.GetConfigurationValuesForPid(productGroup); var globalConfigValues = await _database.GetGlobalConfigurationValues(); // loop through all pidConfigs and override their Pid value if matching global config exists var allConfigs = pidConfigValues.Select(c => { var matchingGlobalConfig = globalConfigValues.FirstOrDefault(g => g.Name == c.Name); if (matchingGlobalConfig != null) { c.Pid = matchingGlobalConfig.Pid; } return c; }).ToList(); // Find all global configs that are not matching any pidConfigValues var productNames = pidConfigValues.Select(p => p.Name).ToArray(); var nonMatchingGlobalConfigs = globalConfigValues.Where(g => !productNames.Contains(g.Name)).ToArray(); // add non-matching global-configs to all-configs collection allConfigs = allConfigs.Concat(nonMatchingGlobalConfigs).ToArray();