Home > Mobile >  Finding differences between 3 complicated dictionaries in C#
Finding differences between 3 complicated dictionaries in C#

Time:05-31

I am having trouble juggling 3 dictionaries to find differences such as missing entries and also property values. The dictionaries key and values are these objects:

public class Car
{
    public string CarBrand{ get; set; }
    public string RentingCompany{ get; set; }
    public string CompanyPhone{ get; set; }
    public ComplexObj MyObj { get; set; } //This is a deserialized XML
}

public class Drivers
{
    public string DriverID{ get; set; } // Unique

    public string Name{ get; set; }

    public string LastName{ get; set; }
}
    public Dictionary<Drivers, List<Car>> List1 = new Dictionary<Drivers, List<Car>>();
    public Dictionary<Drivers, List<Car>> List2 = new Dictionary<Drivers, List<Car>>();
    public Dictionary<Drivers, List<Car>> List3 = new Dictionary<Drivers, List<Car>>();

I need to search in List1.Values all the CarBrands that are not in list2 or List3 and the save the entire KeyValue pair Driver and Value into a new dictionary. I would gladly accept any guidance on what would be an optimal way to approach this.

Thanks

CodePudding user response:

var brands2 = List2.Values.SelectMany(v => v.Select(c => c.CarBrand));
var brands3 = List3.Values.SelectMany(v => v.Select(c => c.CarBrand));
var allBrands = brands2.Concat(brands3);

var keyValuePairsToSave = List1
    .Where(pair => !pair.Value.Any(car => allBrands.Any(brand => brand == car.CarBrand)))
    // or
    //.Where(pair => !allBrands.Any(brand => pair.Value.Any(c => c.CarBrand == brand)))
    .ToArray();
    //or
    //.ToDictionary(pair => pair.Key, pair => pair.Value);

CodePudding user response:

This approach is going to be much much faster than comparing every car brand in list1 with every car brand in list2 and list3. The approach shown in the other answer has high computational complexity, it would scale badly for large amounts of data.

I haven't really tested it, but I think it is correct.

// only the distinct car brands throughout list2 and list3 remain in this hash set
HashSet<string> carBrandsInlist2and3 = new(
    List2.Values
    .Concat(List3.Values)
    .SelectMany(cars => cars.Select(car => car.CarBrand)));

// using a hashset for IsSubsetOf below is going to be much quicker than
// using a 'simple' IEnumerable because set operations have optimizations in place in case
// both sets are of the same type and have the same IEqualityComparer
HashSet<string> tempHashset = new();

Dictionary<Drivers, List<Car>> newDictionary = new(
    List1
    .Where(keyValuePair =>
    {
        // fill the temporary hashset with car brands of this kvp
        tempHashset.Clear();
        tempHashset.UnionWith(keyValuePair.Value.Select(car => car.CarBrand));

        // if tempHashset is not a subset of carBrandsInlist2and3
        // then in this keyValuePair there is a car brand that does not exist in list2 or list3
        
        return !tempHashset.IsSubsetOf(carBrandsInlist2and3);
    }));
  • Related