0

What I need to know:

I only require a true or false answer: Compare each of the Legs by their locations and return true if they are.

What I don't need to know:

Order of locations is irrelevant and duplication is irrelevant.

Data Structure:

CoachDriverItenaryModel (1-*) Leg

Leg (1-*) Exhibitions

(each exhibition has the Location field)

e.g. (simplified in pseudo code... note x,y,z represent locations)

Example 1: The answer should be true...(order is irrelevant)

ListOfLegs.Add(leg1: x,y,z)
ListOfLegs.Add(leg2: z,x,y)
ListOfLegs.Add(leg3: y,z,x)

var answer = ListOfLegs(AreAllLocationsSameOnAllLegs);

Example 2: The answer should be true...(duplication is irrelevant)

ListOfLegs.Add(leg1: x,y,z,y,y,y,y,y)
ListOfLegs.Add(leg2: z,x,y)

var answer = ListOfLegs(AreAllLocationsSameOnAllLegs);

Example 3: The answer should be false...(because no 'z' on leg1)

ListOfLegs.Add(leg1: x,y)
ListOfLegs.Add(leg2: z,x,y)

var answer = ListOfLegs(AreAllLocationsSameOnAllLegs);

Example 4: The answer should be false...(because no 'z' on leg 4)

 ListOfLegs.Add(leg1: x,y,z)
 ListOfLegs.Add(leg2: z,x,y)
 ListOfLegs.Add(leg3: z,x,y,y,y,y)
 ListOfLegs.Add(leg4: x,x,y,x,x)

var answer = ListOfLegs(AreAllLocationsSameOnAllLegs);

I'm looking for a nice Linq statement or something that doesn't require a lengthy algorithm?

below is a project that can be pasted straight in to .Net Fiddle (remember to set the compiler option to Rosyln) and the method to replace is below (it works but is there a better way?)...

public bool CompareAllLegLocations(){}


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var bradford = new Exhibition() { Location = "Bradford", Type = "Eygptian", Price = "£2.00" };
        var leeds = new Exhibition() { Location = "Leeds", Type = "Dinosaurs", Price = "£2.00" };
        var batley = new Exhibition() { Location = "Batley", Type = "Samurai", Price = "£2.00" };
        var york = new Exhibition() { Location = "York", Type = "Vikings", Price = "£2.00" };

        var mondaysItenary = new CoachDriverItenaryModel("Monday");
        mondaysItenary.AddLeg(new Leg { LegNumber = 1, Exhibitions = new List<Exhibition>() { york, leeds, bradford, leeds, york } });
        mondaysItenary.AddLeg(new Leg { LegNumber = 2, Exhibitions = new List<Exhibition>() { batley, leeds, bradford } });

        var tuesdaysItenary = new CoachDriverItenaryModel("Tuesday");
        tuesdaysItenary.AddLeg(new Leg { LegNumber = 1, Exhibitions = new List<Exhibition>() { leeds, batley, leeds } });
        tuesdaysItenary.AddLeg(new Leg { LegNumber = 2, Exhibitions = new List<Exhibition>() { batley, leeds, batley} });

        var wednesdaysItenary = new CoachDriverItenaryModel("Wednesday");
        wednesdaysItenary.AddLeg(new Leg { LegNumber = 1, Exhibitions = new List<Exhibition>() { leeds, bradford, batley } });
        wednesdaysItenary.AddLeg(new Leg { LegNumber = 2, Exhibitions = new List<Exhibition>() { bradford, batley, bradford } });
        wednesdaysItenary.AddLeg(new Leg { LegNumber = 3, Exhibitions = new List<Exhibition>() { bradford, batley, leeds } });

        var thursdaysItenary = new CoachDriverItenaryModel("Thursday");
        thursdaysItenary.AddLeg(new Leg { LegNumber = 1, Exhibitions = new List<Exhibition>() { leeds, bradford, batley, york, leeds } });
        thursdaysItenary.AddLeg(new Leg { LegNumber = 2, Exhibitions = new List<Exhibition>() { batley, bradford, leeds, york } });

        //mondaysItenary.DumpToConsole();
        mondaysItenary.CheckHasSameLocations(); //true:  because same locations on all legs (regardless of order)                   

        Console.WriteLine("-------------------------------");

        //tuesdaysItenary.DumpToConsole();
        tuesdaysItenary.CheckHasSameLocations(); //false: because "york" is not on both legs                    

        Console.WriteLine("-------------------------------");

        //wednesdaysItenary.DumpToConsole();
        wednesdaysItenary.CheckHasSameLocations(); //false: because first leg has "batley" on it and the other leg doesn't

        Console.WriteLine("-------------------------------");

        //thursdaysItenary.DumpToConsole();
        thursdaysItenary.CheckHasSameLocations(); //true: because duplication is allowed so it's okay to go to leeds twice

        Console.WriteLine("Finished");
    }
}

public class CoachDriverItenaryModel
{
    private Dictionary<int, Leg> LegNumberToLegIndex { get; set; }

    public IEnumerable<Leg> Legs => LegNumberToLegIndex?.Values;   //null propagation operator (c# 6+) use Rosyln 1.0.0 compiler

    public string Day { get; set; }

    public CoachDriverItenaryModel(string day) //constructor
    {
        LegNumberToLegIndex = new Dictionary<int, Leg>();
        Day = day;
    }   

    public void AddLeg(Leg leg)
    {
        if (LegNumberToLegIndex == null)
        {
            LegNumberToLegIndex = new Dictionary<int, Leg>();
        }

        if (!LegNumberToLegIndex.ContainsKey(leg.LegNumber))        
        {
            LegNumberToLegIndex.Add(leg.LegNumber, leg);            
        }                
    }

    public void DumpToConsole()
    {
        Console.WriteLine($"Day: {this.Day}");
        foreach (var displayLeg in this.Legs)
        {
            Console.WriteLine($"leg: {displayLeg.LegNumber}");
            foreach (var exhibition in displayLeg.Exhibitions)
            {
                Console.WriteLine($"Exhibition: {exhibition.Location}, Type: {exhibition.Type}, Price:{exhibition.Price}");
            }
        }
    }

    public bool CheckHasSameLocations()
    {
        if (LegNumberToLegIndex.Count <= 1) return true;

        for (var i=0; i < LegNumberToLegIndex.Count()-1; i++)
        {
            Leg leg = LegNumberToLegIndex[LegNumberToLegIndex.ElementAt(i).Key];
            Leg nextLeg = LegNumberToLegIndex[LegNumberToLegIndex.ElementAt(i + 1).Key];

            var legUnqOrd = from l in leg.Exhibitions.Distinct()
                                orderby l.Location
                                select new { l.Location };

            var nextLegUnqOrd = from l in nextLeg.Exhibitions.Distinct()
                            orderby l.Location
                            select new { l.Location };

            if (!legUnqOrd.SequenceEqual(nextLegUnqOrd))
            {
                Console.WriteLine("!Locations are different!");
                return false;
            }
        }
        Console.WriteLine("Locations Match");
        return true;
    }
}

public class Leg
{
    public int LegNumber { get; set; }
    public List<Exhibition> Exhibitions { get; set; }
}

public class Exhibition
{
    public string Location { get; set; }
    public string Type { get; set; }
    public string Price { get; set; }
}
MagicLuckyCat
  • 324
  • 2
  • 5
  • 19
  • yes certainly this is easily solvable by Linq. unfortunately i have no idea what exactly you are after. solve the latter and the former can be solved too :) perhaps show the data structure of what exactly you want: because this wasn't clear (to me at least): I'm trying to aggregate all distinct "Exhibition->Location(s)" for each "Leg" and then compare the legs to make sure they contain the same "Locations".." – BenKoshy Feb 09 '17 at 14:54
  • I've added the data structure and chopped out some of the fluffiness! – MagicLuckyCat Feb 09 '17 at 15:21
  • excellent!!!! This is what people want to see. make it easy for them to answer your question and you've already got an answer :) – BenKoshy Feb 09 '17 at 21:18

1 Answers1

1

You need to get the distinct locations from all the exhibitions and sort them for each of the legs. Once you have location list for each of the legs you need to pick one list and compare it with rest of all the lists and when the comparision fails that mean that the exhibitions are not equal and that says that the legs are not matching.

Method CompareAllLegLocations would look as following.

public bool CompareAllLegLocations()
    {
        if (_legNumberToLegIndex.Count > 0)
        {
            if (_legNumberToLegIndex.Count == 1)
                return false;

            var legs = _legNumberToLegIndex.Values;
            var firstLeg = _legNumberToLegIndex.FirstOrDefault().Value; // Taking first leg to determine the distinct list of locations.
            var firstLegLocations = firstLeg.Exhibitions.Select(ex => ex.Location).Distinct().OrderBy(x => x); // Determining distinct and ordered list of locations.
            foreach (var leg in legs)
            {
                var locations = leg.Exhibitions.Select(ex => ex.Location).Distinct().OrderBy(x => x); //Determining distinct and order list of locations for each of the leg.

                if (!locations.SequenceEqual(firstLegLocations)) //Comparing the list of locations of current leg to that of the first leg.
                    return true;
            }
            return false;
        }
        return false;
    }

I have assumed, from the question, that the comparison criteria is only location. If you have to compare exhibitions based on all the three properties of it then you need to create an EqualityComparer and use it to get the distinct exhibitions.

public class ExhibitionComparer : IEqualityComparer<Exhibition>
{
    public bool Equals(Exhibition x, Exhibition y)
    {
        return x.Location == y.Location && x.Type == y.Type && x.Price == y.Price;
    }

    public int GetHashCode(Exhibition obj)
    {
        return obj.GetHashCode();

    }
}

And use this comparer as following.

var firstLegExhibitions = firstLeg.Exhibitions.Distinct(comparer).OrderBy(ex => ex.Location).ToList();

This should resolve the issue. You can refine this code and logic as per your convenience.

Chetan
  • 6,711
  • 3
  • 22
  • 32