简体   繁体   中英

Compare elements of an object resides in two list - one on one using LINQ

I'm trying to find out is there any better way other than Enumerable.Range in WHERE clause to compare object's elements one on one.

It could be a parallel since We're comparing one on one here.

For example: House.Windows[0].color != House1.Windows[0].color and then movenext to House.Windows[1].color != House1.Windows[1].color and so on...

Type will be same in both list.

    public class House
{
    string HouseNmbr;
    List<Window> windows;

}

public class Window
{
    string WSize;
    string WColor;
    bool IsEnergyEff;
}

public static class MyMain
{
    void Main()
    {
        House h1 = new House
        {
            HouseNmbr = "1",
            windows = new List<Window> { 
                new Window {Wsize="1", WColor = "blue",IsEnergyEff = true},
                new Window {Wsize="1", WColor = "black"},
                new Window {Wsize="1", WColor = "red"}
            }
        };

        House h2 = new House
        {
            HouseNmbr = "1",
            windows = new List<Window> { 
                new Window {Wsize="2", WColor = "blue",IsEnergyEff = false},
                new Window {Wsize="2", WColor = "black"}
            }
        };

        //Find the diffs...
        IEnumerable<House> updatesFromHouses = from id in h2 //Since h2 will have updates
                                             join pd in h1
                                             on id.HouseNmbr equals pd.HouseNmbr
                                               select new House
                                             {
                                                 windows = pd.windows.Where(
                                                    wn => Enumerable.Range(0, wn.windows.Count).All(ctr => wn.IsEnergyEff != id.windows[ctr].IsEnergyEff)
                                                 ).ToList()
                                             };            

    }
}

Use Enumerable.Zip if you are comparing one by one:

House.Windows.Zip(House1.Windows, (w, w1) => w.color != w1.color);

This returns collection of boolean values for one by one comparison of colors. You can use Any(b => !b) to check if there is any non equal color.

Keep in mind, that both windows lists should have same length (only corresponding elements will produce result). So, you can start from checking length of lists before doing zip. If items count is different, then lists are not same.


In order to compare windows you should override Equals and GetHashCode methods:

public class Window
{
    public string Size { get; set; }
    public string Color { get; set; }
    public bool IsEnergySaving { get; set; }

    public Window() { }

    public Window(string size, string color, bool isEnergySaving)
    {
        Size = size;
        Color = color;
        IsEnergySaving = isEnergySaving;
    }

    public override bool Equals(object obj)
    {
        Window other = obj as Window;
        if (other == null)
            return false;

        return Color == other.Color &&
               IsEnergySaving == other.IsEnergySaving;
    }

    public override int GetHashCode()
    {
        int hash = 19;            
        hash = hash * 23 + Color.GetHashCode();
        hash = hash * 23 + IsEnergySaving.GetHashCode();
        return hash;
    }
}

Here is house class slightly improved:

public class House
{
    public House(string number)
    {
        Number = number;
        Windows = new List<Window>();
    }

    public string Number { get; private set; }
    public List<Window> Windows { get; private set; }

    public House WithWindow(string size, string color, bool energySaving = false)
    {
        Windows.Add(new Window(size, color, energySaving));
        return this;
    }
}

With this fluent API you can create houses like this:

House h1 = new House("1")
                .WithWindow("1", "blue", true)
                .WithWindow("1", "black")
                .WithWindow("1", "red");

House h2 = new House("1")
                .WithWindow("2", "blue")
                .WithWindow("2", "black");

And finding changed and new windows will look like:

var changedAndNewWindows = h2.Windows.Except(h1.Windows);

You can use Parallel.For in this context since you are comparing two lists element by element and without editing (if you need to edit you have to use lock):

var count = Math.Min(h1.Windows.Count, h2.Windows.Count);
Parallel.For(0, count, (index)=>{
//Do your operations here
if(h1.Windows[index].Color == h2.Windows[index].Color)
{
}
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM