Reputation: 22453
I have several classes in my c# application.
I have a plant class with a constructor that takes a name and a weight.
Then I have a Fruit class that inherits plant and adds the number of seeds attribute.
Also I have a Veg class that inherits from plant and adds the savoryLevel attribute.
fruit and veg can be added to their lists by the user.
I have overloaded the == operator in fruit so that it compares the names of fruit and veg and if they have the same name it tells you. My issue is when I try to compare the whole lists to find duplication, I just cant get the code to work at all.
here is some of my code plant class
public string name;
public string weight;
public Plant(string name, string weight)
{
this.name = name;
this.email = weight;
}
....
public static bool operator ==(Plant a, Plant b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
// Return true if the fields match:
return a.name == b.name;
}
then the new fruit constructor
string seeds;
public fruit(string name, string weight, string seeds)
: base(name, weight)
{
this.seeds
}
here is veg
string savoryLevel;
public fruit(string name, string weight, string savouryLevel)
: base(name, weight)
{
this.savoryLevel
}
here is the main where I compare 2 instances, this works fine
Fruit f = new Fruit("apple", "2", "5");
Veg v = new Veg("carrot", "3", "7");
if (f == v)
{
Console.WriteLine("They are the same");
}
else{
Console.WriteLine("They are different");
}
This is the tricky part, I need to iterate through my entire list of veg and fruit and see if any of the fruit have the same name as the veg.
using the lists directly wont work
List<Fruit> fr = new List<Fruit>();
List<Veg> ve = new List<Veg>();
if(fr == ve){
Console.....
}
else{
Console....
}
So how do I get the lists to compare and print out some result to say these are the same or these are not the same? Any help is really appreciated, thanks. please just ask if you would like more info.
Upvotes: 0
Views: 656
Reputation: 22453
First off thanks everyone for the input, You've all helped me see the problem more clearly. But Overloading the == operator is something I had to do as part of the requirements.
I have however found a relatively simple way to compare the 2 lists that uses the overloaded == operator I added to the Plant Class
By nesting a forEach loop I check every list item of veg against every list item of fruit.
public void Compare(List<Fruit> frList, List<Veg> vList)
{
foreach (Fruit f in frList)
{
foreach (Veg v in vList)
{
if (f == v)
{
//some functionality
}else{
//some other funtionality
}
}
}
}
This still uses the overloaded == operator in plant and will only compare the name when I call the the method in the main. i.e. even if the plants have different weights they will be considered the same.
Thanks again for the input guys.
Upvotes: 0
Reputation: 29264
I think you should use IEquatable<Plant>
and cast the lists into List<Plant>
with SequenceEquals()
Demo:
public class Plant : IEquatable<Plant>
{
public string Name { get; set; }
public string Weight { get; set; }
public override bool Equals(object obj)
{
var other=obj as Plant;
if(other!=null)
{
return Equals(other);
}
return false;
}
public bool Equals(Plant other)
{
Debug.WriteLine("Checking Equality Between {0} And {1}", Name, other.Name);
return Name.Equals(other.Name);
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
public class Fruit : Plant
{
public string Seeds { get; set; }
}
public class Veg : Plant
{
public string SavoryLevel { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<Fruit> fruits=new List<Fruit>() {
new Fruit() { Name="apple", Weight = "2", Seeds="5" },
new Fruit() { Name="banana", Weight="1", Seeds="30" }
};
List<Veg> veggies=new List<Veg>() {
new Veg() { Name = "carrot", Weight="3", SavoryLevel="7" },
new Veg() { Name = "potato", Weight="5", SavoryLevel="1" }
};
var equal=fruits.Cast<Plant>().SequenceEqual(veggies);
var unique_fruits=fruits.Distinct();
}
}
It produces the output
Checking Equality Between apple And carrot
and then the equality comparison ends (since it is false). The point being is that it calls the appropriate Equals()
function.
Upvotes: 2
Reputation: 4002
You really don't need to overload the Equals
method to find out if something is different. Overloading the Equals
method should be used if you are looking for a different behaviour, not for different results.
Since this case compares two string members in two different classes, why not just use LINQ
to compare the members themselves which are of the same datatype?
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
public static void Main()
{
List<Fruit> f = new List<Fruit>();
Fruit fTemp = new Fruit() { name = "Kiwi" };
f.Add(fTemp);
fTemp = new Fruit() { name = "Tomato" };
f.Add(fTemp);
List<Veg> v = new List<Veg>();
Veg vTemp = new Veg() { name = "Tomato" };
v.Add(vTemp);
List<Veg> vDuplicates = v.Where(vegToCompare=>f.Any(fruitToCompare=>fruitToCompare.name.Equals(vegToCompare.name))).ToList();
vDuplicates.ForEach(a=>Console.WriteLine(a.name));
Console.WriteLine("Number of Duplicates Found: " + vDuplicates.Count);
}
}
public class Fruit
{
public string name;
}
public class Veg
{
public string name;
}
Upvotes: 1
Reputation: 13286
I'd use LINQ, and rather that (or in addition to) overloading the ==
operator, go for the "more native" object.Equals
and object.GetHashCode
.
public override int GetHashCode()
{
return this.name.GetHashCode();
}
public override bool Equals(object b)
{
Plant bPlant = b as Plant;
// If one is null, but not both, return false.
if (bPlant == null)
{
return false;
}
// Return true if the fields match:
return this.name == b.name;
}
Then you can use LINQ:
return fr.SequenceEquals(ve);
Note, of course, that, as the name implies, this only works when fr
and ve
are exactly equal. That is to say, the order must be the same between them: if both contain "Carrot, Broccoli," you'll be fine, but if one is that and the other is "Broccoli, Carrot," this will return false.
Unless I'm misunderstanding, and in fact you want the intersection, not to know that they're equal, in which case:
return fr.Intersect(ve);
Upvotes: 1
Reputation: 24395
if you want to to it per item, you could do it like this
foreach(var fruit in fr)
{
if(ve.Any(x => x.Name == fruit.Name))
{
Console.Write(fruit.Name + " is in both lists");
}
}
Upvotes: 1
Reputation: 101701
If you wanna compare the items at the same index Zip
method can be useful:
bool result = fr.Zip(ve, (f,v) => new { f, v }).All(x => x.f == x.v);
Zip
methods create pairs of corresponding items, then put each pair into an anonymous type. And All
method simply checks if all items in the pairs are equal.
Upvotes: 1