比较 2 个对象列表
Comparing 2 lists of objects
我的 C# 应用程序中有几个 classes。
我有一个工厂 class,其构造函数需要一个名称和一个权重。
然后我有一个Fruit class 继承了plant 并添加了seeds 属性
我还有一个 Veg class 继承自 plant 并添加了 savoryLevel 属性。
用户可以将水果和蔬菜添加到他们的列表中。
我在 fruit 中重载了 == 运算符,以便它比较 fruit 和 veg 的名称,如果它们具有相同的名称,它会告诉你。我的问题是当我尝试比较整个列表以查找重复项时,我根本无法让代码工作。
这是我的一些代码
植物 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;
}
然后是新的水果构造函数
string seeds;
public fruit(string name, string weight, string seeds)
: base(name, weight)
{
this.seeds
}
这是蔬菜
string savoryLevel;
public fruit(string name, string weight, string savouryLevel)
: base(name, weight)
{
this.savoryLevel
}
这是我比较 2 个实例的主要部分,效果很好
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");
}
这是棘手的部分,我需要遍历整个蔬菜和水果列表,看看是否有任何水果与蔬菜同名。
直接使用列表是行不通的
List<Fruit> fr = new List<Fruit>();
List<Veg> ve = new List<Veg>();
if(fr == ve){
Console.....
}
else{
Console....
}
那么如何获取列表进行比较并打印出一些结果来说明它们相同或不同?
非常感谢任何帮助,谢谢。
请询问您是否需要更多信息。
如果你想比较相同索引的项目 Zip
方法很有用:
bool result = fr.Zip(ve, (f,v) => new { f, v }).All(x => x.f == x.v);
Zip
方法创建成对的对应项,然后将每对放入匿名类型。 All
方法只是检查对中的所有项目是否相等。
如果你想对每个项目进行处理,你可以这样做
foreach(var fruit in fr)
{
if(ve.Any(x => x.Name == fruit.Name))
{
Console.Write(fruit.Name + " is in both lists");
}
}
我会使用 LINQ,而不是(或除此之外)重载 ==
运算符,选择 "more native" object.Equals
和 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;
}
然后你可以使用 LINQ:
return fr.SequenceEquals(ve);
当然请注意,顾名思义,这仅在 fr
和 ve
完全 相等时有效。也就是说,它们之间的顺序必须相同:如果都包含 "Carrot, Broccoli," 你会没事的,但如果一个是那个,另一个是 "Broccoli, Carrot," 这将 return false .
除非我误会了,其实你想要交集,不知道他们是相等的,这样的话:
return fr.Intersect(ve);
您真的不需要重载 Equals
方法来查明是否有不同。如果您正在寻找不同的行为而不是不同的结果,则应使用重载 Equals
方法。
既然本例比较两个不同 类 中的两个字符串成员,为什么不直接使用 LINQ
来比较具有相同数据类型的成员本身呢?
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;
}
我认为您应该使用 IEquatable<Plant>
并使用 SequenceEquals()
将列表转换为 List<Plant>
演示:
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();
}
}
它产生输出
Checking Equality Between apple And carrot
然后相等比较结束(因为它是假的)。关键是它调用了适当的 Equals()
函数。
首先感谢大家的意见,你们都帮助我更清楚地看到了问题。
但是重载 == 运算符是我必须做的部分要求。
然而,我找到了一种相对简单的方法来比较使用我添加到 Plant 的重载 == 运算符的 2 个列表 Class
通过嵌套 forEach 循环,我检查了蔬菜的每个列表项与水果的每个列表项。
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
}
}
}
}
这仍然在 plant 中使用重载的 == 运算符,并且只会在我调用 main 中的方法时比较名称。即,即使植物的重量不同,它们也将被视为相同。
再次感谢您的输入。
我的 C# 应用程序中有几个 classes。
我有一个工厂 class,其构造函数需要一个名称和一个权重。
然后我有一个Fruit class 继承了plant 并添加了seeds 属性
我还有一个 Veg class 继承自 plant 并添加了 savoryLevel 属性。
用户可以将水果和蔬菜添加到他们的列表中。
我在 fruit 中重载了 == 运算符,以便它比较 fruit 和 veg 的名称,如果它们具有相同的名称,它会告诉你。我的问题是当我尝试比较整个列表以查找重复项时,我根本无法让代码工作。
这是我的一些代码 植物 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;
}
然后是新的水果构造函数
string seeds;
public fruit(string name, string weight, string seeds)
: base(name, weight)
{
this.seeds
}
这是蔬菜
string savoryLevel;
public fruit(string name, string weight, string savouryLevel)
: base(name, weight)
{
this.savoryLevel
}
这是我比较 2 个实例的主要部分,效果很好
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");
}
这是棘手的部分,我需要遍历整个蔬菜和水果列表,看看是否有任何水果与蔬菜同名。
直接使用列表是行不通的
List<Fruit> fr = new List<Fruit>();
List<Veg> ve = new List<Veg>();
if(fr == ve){
Console.....
}
else{
Console....
}
那么如何获取列表进行比较并打印出一些结果来说明它们相同或不同? 非常感谢任何帮助,谢谢。 请询问您是否需要更多信息。
如果你想比较相同索引的项目 Zip
方法很有用:
bool result = fr.Zip(ve, (f,v) => new { f, v }).All(x => x.f == x.v);
Zip
方法创建成对的对应项,然后将每对放入匿名类型。 All
方法只是检查对中的所有项目是否相等。
如果你想对每个项目进行处理,你可以这样做
foreach(var fruit in fr)
{
if(ve.Any(x => x.Name == fruit.Name))
{
Console.Write(fruit.Name + " is in both lists");
}
}
我会使用 LINQ,而不是(或除此之外)重载 ==
运算符,选择 "more native" object.Equals
和 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;
}
然后你可以使用 LINQ:
return fr.SequenceEquals(ve);
当然请注意,顾名思义,这仅在 fr
和 ve
完全 相等时有效。也就是说,它们之间的顺序必须相同:如果都包含 "Carrot, Broccoli," 你会没事的,但如果一个是那个,另一个是 "Broccoli, Carrot," 这将 return false .
除非我误会了,其实你想要交集,不知道他们是相等的,这样的话:
return fr.Intersect(ve);
您真的不需要重载 Equals
方法来查明是否有不同。如果您正在寻找不同的行为而不是不同的结果,则应使用重载 Equals
方法。
既然本例比较两个不同 类 中的两个字符串成员,为什么不直接使用 LINQ
来比较具有相同数据类型的成员本身呢?
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;
}
我认为您应该使用 IEquatable<Plant>
并使用 SequenceEquals()
List<Plant>
演示:
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();
}
}
它产生输出
Checking Equality Between apple And carrot
然后相等比较结束(因为它是假的)。关键是它调用了适当的 Equals()
函数。
首先感谢大家的意见,你们都帮助我更清楚地看到了问题。 但是重载 == 运算符是我必须做的部分要求。
然而,我找到了一种相对简单的方法来比较使用我添加到 Plant 的重载 == 运算符的 2 个列表 Class
通过嵌套 forEach 循环,我检查了蔬菜的每个列表项与水果的每个列表项。
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
}
}
}
}
这仍然在 plant 中使用重载的 == 运算符,并且只会在我调用 main 中的方法时比较名称。即,即使植物的重量不同,它们也将被视为相同。
再次感谢您的输入。