更有效地查找列表中的所有元素

本文关键字:元素 有效地 查找 列表 | 更新日期: 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方法来比较两个列表。