C# 如何在比较两个列表的基础上将属性更新为true或false
我有两张单子C# 如何在比较两个列表的基础上将属性更新为true或false,c#,linq,C#,Linq,我有两张单子 class obj1 { public string country{ get; set; } public string region{ get; set; } } class obj2 { public string country{ get; set; } public string region { get; set; } public string XYZ { get; set; } public bool ToBeChanged{
class obj1
{
public string country{ get; set; }
public string region{ get; set; }
}
class obj2
{
public string country{ get; set; }
public string region { get; set; }
public string XYZ { get; set; }
public bool ToBeChanged{ get; set; }
}
List<obj1> alist = new List<obj1>();
alist.Add("US", "NC");
alist.Add("US", "SC");
alist.Add("US", "NY");
List alist=newlist();
添加(“美国”、“北卡罗来纳州”);
添加(“美国”、“SC”);
添加(“美国”、“纽约”);
list alist2
)可能包含1000个条目,其中包含许多国家和地区的组合
瓦伊巴夫评论中的两点和我的想法:
- 有些人不确定你的匹配标准到底是什么。但在我看来,很明显,你在“国家”和“地区”上是匹配的。然而,在未来,请明确说明这一点
- 有一条评论批评了您对变量名的选择。这种批评是完全有道理的。当您对代码所做的事情几乎没有任何提示时,代码更容易维护,而变量名对于这一点至关重要
class RegionInfo {
public RegionInfo(string country, string region) {
this.country = country;
this.region = region;
}
public string country{ get; set; }
public string region{ get; set; }
}
class obj2 {
public obj2 (string country, string region, string XYZ) {
this.country = country;
this.region = region;
this.XYZ = XYZ;
}
public string country{ get; set; }
public string region { get; set; }
public string XYZ { get; set; }
public bool ToBeChanged{ get; set; }
}
我使用LINQ联接来匹配这两个列表,只输出联接的“obj2”端,然后循环结果以切换“ToBeChanged”值
var regionInfos = new List<RegionInfo>() {
new RegionInfo("US", "NC"),
new RegionInfo("US", "SC"),
new RegionInfo("US", "NY")
};
var obj2s = new List<obj2> {
new obj2("US", "NC", "What am I for?"),
new obj2("US", "SC", "Like, am I supposed to be the new value?"),
new obj2("CA", "OT", "XYZ doesn't have a stated purpose")
};
var obj2sToChange = obj2s
.Join(
regionInfos,
o2 => new { o2.country, o2.region },
reg => new { reg.country, reg.region },
(o2,reg) => o2
);
foreach (var obj2 in obj2sToChange)
obj2.ToBeChanged = true;
obj2s.Dump(); // using Linqpad, but you do what works to display
var regioninfo=新列表(){
新区域信息(“美国”、“北卡罗来纳州”),
新区域信息(“美国”、“SC”),
新区域信息(“美国”、“纽约”)
};
var obj2s=新列表{
新obj2(“美国”、“北卡罗来纳州”、“我是干什么的?”),
新的obj2(“我们”、“SC”、“我应该是新值吗?”),
新obj2(“CA”、“OT”、“XYZ无明确目的”)
};
var obj2sToChange=obj2s
.加入(
区域信息,
o2=>新{o2.国家,o2.地区},
reg=>新{reg.country,reg.region},
(o2,reg)=>o2
);
foreach(obj2sToChange中的变量obj2)
obj2.ToBeChanged=true;
obj2s.Dump();//使用Linqpad,但您要做的就是显示
这导致:
国家
区域
XYZ
改变
美国
数控
我是干什么的?
真的
美国
联合国安全理事会
比如,我应该成为新的价值观吗?
真的
加利福尼亚州
OT
XYZ没有明确的用途
假的
首先,使用LINQ,您永远无法更改源代码。您只能从源中提取数据。之后,可以使用提取的数据更新源 如果第二个(alist2)列表属性(国家和地区)与第一个(alist1)匹配,则需要将属性“ToBeChanged”更新为“True”,否则为false 这不是一个适当的要求
alist1
是一系列obj1
对象。我认为,如果alist1中的任何obj1项的[country,region]组合与相关obj2的[country,region]组合相匹配,则您希望某个obj2的属性被更改为true
要求获取alist2中的所有obj2,这些obj2的[country,region]组合与alist1中obj1对象的任何[country,region]组合相匹配
您可能考虑过使用Where
进行此操作。类似于“其他列表中[国家、地区]组合的位置”。每当您需要查找一个项目是否在另一个列表中时,请考虑使用的重载之一。
问题是,每个obj2中的[Country,Region]组合都可以转换为obj1类的对象,但如果要检查它们是否相等,则需要按引用进行比较,而需要按值进行比较
IEqualityComparer<obj1> comparer = Obj1Comparer.ByValue;
IEnumerable<obj2> obj2sThatNeedToBeChanged = alist2.Select(obj2 => new
{
Obj1 = new Obj1
{
Country = obj2.Country,
Region = obj2.Region,
},
Original = obj2,
})
.Where(item => alist.Contains(item.CountryRegionCombination, comparer))
.Select(item => item.Original);
有两种解决方案:
- 创建按值比较obj1的EqualityComparer
- 创建[国家,地区]作为匿名类型。匿名类型总是按值进行比较
var eligibleCountryRegionCombinations = alist.Select(obj1 => new
{
Country = obj1.Country,
Region = obj1.Region,
});
注意,最后我没有使用ToList:创建了可枚举项,但序列还没有被枚举。在LINQ术语中,这称为延迟执行或延迟执行
IEnumerable<obj2> obj2sThatNeedToBeChanged = alist2.Select(obj2 => new
{
CountryRegionCombination = new
{
Country = obj2.Country,
Region = obj2.Region,
},
Original = obj2,
})
.Where(item => eligibleCountryRegionCombinations.Contains(
item.CountryRegionCombination))
.Select(item => item.Original);
更改正在枚举的源可能很危险。在这种情况下,这不是问题,因为您更改的字段不用于创建枚举。不过,我认为,由于将来可能会发生变化,在开始更改源代码之前先做一个收费列表更安全
创建一个相等比较器
Enumerable.Contains的重载之一具有参数比较器。这需要一个IEqualityComparer
返回哪个HashCode取决于调用的频率,例如在字典、Contains等比较器中
这些国家和地区有多“不同”?不同的国家可能也意味着不同的地区。因此,如果只计算国家的散列码,可能就足够有效了。如果一个国家有很多很多地区,那么如果一个地区只在一个国家(OberAmmerGau可能只在德国),或者只有几个地区(会有多少个“新阿姆斯特丹”地区),那么计算地区的哈希代码可能会更好,那么您根本不必检查该国家
因为我们有一个相等比较器,所以不需要将alist转换为匿名类型,我们可以指定包含的
应按值进行比较
IEqualityComparer<obj1> comparer = Obj1Comparer.ByValue;
IEnumerable<obj2> obj2sThatNeedToBeChanged = alist2.Select(obj2 => new
{
Obj1 = new Obj1
{
Country = obj2.Country,
Region = obj2.Region,
},
Original = obj2,
})
.Where(item => alist.Contains(item.CountryRegionCombination, comparer))
.Select(item => item.Original);
IEqualityComparer comparer=Obj1Comparer.ByValue;
需要更改的IEnumerable OBJ2ST=alist2。选择(obj2=>new
{
Obj1=新Obj1
{
国家=对象J2.国家,
区域=对象J2。区域,
},
public override int GetHashCode (obj1 x)
{
if (x == null) return 87966354; // just a number
return CountryComparer.GetHashCode(x.Country)
^ RegionComparer.GetHashCode(x.Region);
}
IEqualityComparer<obj1> comparer = Obj1Comparer.ByValue;
IEnumerable<obj2> obj2sThatNeedToBeChanged = alist2.Select(obj2 => new
{
Obj1 = new Obj1
{
Country = obj2.Country,
Region = obj2.Region,
},
Original = obj2,
})
.Where(item => alist.Contains(item.CountryRegionCombination, comparer))
.Select(item => item.Original);
private static IEqualityComparer<string> CountryComparer => StringComparer.OrdinalIgnoreCase;
private static IEqualityComparer<string> RegionComparer => StringComparer.OrdinalIgnoreCase;
public static IEnumerable<Obj2> WhereSameLocation(
this IEnumerable<Obj2> source,
IEnumerable<Obj1> obj1Items)
{
// TODO: what to do if source == null?
foreach (Obj2 obj2 in source)
{
// check if there is any obj1 with same [Country, Region]
if (obj1Items
.Where(obj1 => CountryComparer.Equals(obj2.Country, obj1.Country)
&& RegionComparer.Equals(obj2.Region, obj1.Region))
.Any())
{
yield return obj2;
}
}
}
IEnumerable<Obj1> alist = ...
IEnumerable<Obj2> alist2 = ...
IEnumerable<obj2> obj2sThatNeedToBeChanged = alist2.WhereSameLocation(alist);