更有效地查找列表中的所有元素
本文关键字:元素 有效地 查找 列表 | 更新日期: 2023-09-27 18:01:24
我得到了这个代码:
List<string> values = getValues();
Details detailsData = getDetails();
if (values[0].Equals(detailsData.Attr1))
if (values[1].Equals(detailsData.Attr2))
if (values[2].Equals(detailsData.Attr3))
if (values[3].Equals(detailsData.Attr4))
if (values[4].Equals(detailsData.Attr5))
return true;
getValues()
返回一个字符串列表,我希望(^^)存在于Details
对象上。
是否有更有效或更"漂亮"的方法来实现上面的代码?
编辑
class Details : MainDetails
{
string Attr3{ get; set; }
string Attr4{ get; set; }
string Attr5{ get; set; }
}
class MainDetails
{
string Attr1{ get; set; }
string Attr2{ get; set; }
}
顺便说一句,可能有一些其他的对象,如Details,扩展MainDetails并需要此验证。这段代码会被多次使用
简单改进:
if (values[0].Equals(detailsData.Attr1) &&
values[1].Equals(detailsData.Attr2) &&
values[2].Equals(detailsData.Attr3) &&
values[3].Equals(detailsData.Attr4) &&
values[4].Equals(detailsData.Attr5))
{
return true;
}
如果你只在一个位置这样做,我就不会再麻烦了。如果你在几个地方做同样的事情,你可以考虑设置一个函数,例如把你的Details
变成另一个List<string>
,然后用SequenceEquals
来比较它们。
编辑:虽然我越考虑它,越觉得比较字符串的平面列表类的层次结构似乎是一个坏主意,这里有一个例子,你可以如何做到这一点在一个可扩展的方式。基类"使用"前两个值,然后交给派生类检查剩余的值:
class MainDetails
{
string Attr1 { get; set; }
string Attr2 { get; set; }
protected virtual bool Matches(IEnumerator<string> e)
{
// Check the first two items exist and match
return
e.MoveNext() && e.Current.Equals(Attr1) &&
e.MoveNext() && e.Current.Equals(Attr2);
}
public bool Matches(IEnumerable<string> details)
{
using (var e = details.GetEnumerator())
{
// Check the details match. (Optionally check
// that there are no "extra" details.)
return Matches(e); // && !e.MoveNext();
}
}
}
class Details : MainDetails
{
string Attr3 { get; set; }
string Attr4 { get; set; }
string Attr5 { get; set; }
protected override bool Matches(IEnumerator<string> e)
{
// Check the MainDetails match, and the next three too.
return base.Matches(e) &&
e.MoveNext() && e.Current.Equals(Attr3) &&
e.MoveNext() && e.Current.Equals(Attr4) &&
e.MoveNext() && e.Current.Equals(Attr5);
}
}
...
List<string> values = getValues();
Details detailsData = getDetails();
if (detailsData.Matches(values))
return true;
我不确定你确切的用例,但希望这能给你一些想法。
如果你不能改变你的属性到所有的数组,那么你至少可以写一点更漂亮的代码…虽然这是非常主观的 !
List<string> values = getValues();
Details detailsData = getDetails();
if
(
values[0].Equals(detailsData.Attr1) &&
values[1].Equals(detailsData.Attr2) &&
values[2].Equals(detailsData.Attr3) &&
values[3].Equals(detailsData.Attr4) &&
values[4].Equals(detailsData.Attr5)
)
{
return true;
}
如果你想要一个干净的代码,你可以在你的类上放一些索引器。
class Details : MainDetails
{
string Attr3 { get; set; }
string Attr4 { get; set; }
string Attr5 { get; set; }
public override string this[int index]
{
get
{
switch (index)
{
case 3:
return Attr3;
case 4:
return Attr4;
case 5:
return Attr5;
}
return base[index];
}
}
}
class MainDetails
{
string Attr1 { get; set; }
string Attr2 { get; set; }
public virtual string this[int index]
{
get
{
switch (index)
{
case 1:
return Attr1;
case 2:
return Attr2;
default:
throw new NotImplementedException();
}
}
}
}
这样就可以使用for循环来比较
for(int i = 0; i < 5; i++)
{
if(values[i] != detailsdata[i+1])
return false;
}
return true;
同样可以通过在类上放置一个方法来实现,如getattributvalue (int i);
当您的属性像那样命名时,没有更"清晰"的方法来做到这一点。您可以使用反射(以节省2行代码),但这会遇到性能问题。
我会这样写
List<string> values = getValues();
Details detailsData = getDetails();
if (values.SequenceEqual(new[] { detailsData.Attr1, detailsData.Attr2, detailsData.Attr3, detailsData.Attr4, detailsData.Attr5, }))
return true;
使用LINQ的SequenceEqual
扩展方法,参见MSDN: Enumerable.SequenceEqual<TSource>
。
除了罗林斯的回答。将details对象转换为列表的函数可能如下所示:
private static IEnumerable<string> GetDetailProperties(Details details) {
yield return details.Attr1;
yield return details.Attr2;
yield return details.Attr3;
yield return details.Attr4;
yield return details.Attr5;
}
您可以使用SequenceEquals方法来比较两个列表。