繁体   English   中英

C#获取使用结构的两个列表之间的差异

[英]c# get difference between two lists that use structs

这是我的第一篇文章。 我在C#中相当陌生,并且正在尝试使用结构类型的列表。

public struct MyStruct
{
    public string Field1;
    public string Field2;
}

List<MyStruct> BigList = new List<MyStruct> { };
List<MyStruct> SmallList = new List<MyStruct> { }; 

到目前为止,我所做的一切都使用了已知的类型(例如,字符串),但是对于上面示例中的列表,我无法使用任何具有肯定结果的函数。

目前,其想法是获得使用该结构类型(列表)的两个列表之间的差异。 BigList将始终具有比Small列表更多的项目,其想法是考虑到Field1,在SmalList中查找BigList中不存在的所有项目。 理想情况下,结果可以是相同类型的列表(列表)。

这可能吗? 我已经尝试了一些在stackoverflow中找到的示例,但是找不到许多使用结构列表的示例,而我尝试过的示例却无效。

一个适用于字符串列表的示例:

var Missing = BigList.Except(SmallList).ToList() 

可能是一个解决方案,但我需要查看一个字段(结构的Field1),而不仅仅是一个简单的字符串。

对于这些类型的列表,使用.Sort或.Contains不能产生肯定的结果(专门查看结构的一个字段,例如List)。

有人能帮我吗? 那很好啊!

提前致谢。 问候,

就像其他人所说的,在您的示例中使用struct尤其是由于您是C#的新手,可能不是真正的好主意,而是更多的错误。 我建议您用一个类替换您的结构。

您面临的问题是,因为您使用的是自己定义的类型,所以比较将无法正常工作,或者至少无法正常工作。

它不会知道如何比较两个对象,如果是类,则将验证它是否是同一对象,如果是结构,则将进行字节对字节的比较(如果该结构不包含引用类型)或比较它包含的引用是否相同(如果结构包含引用类型)。

使一切正常工作所需要做的是重写类中的Equals方法。 请参阅此MSDN文章以开始使用它: https : //msdn.microsoft.com/zh-cn/library/336aedhh(v=vs.100).aspx

另外,您可以为您的类型实现IEqualityComparer。 如果您无权访问类实现,则它特别有用。 检查此MSDN文章以执行此操作: https : //msdn.microsoft.com/zh-cn/library/bb300779(v=vs.110).aspx

有很多方法可以解决此问题。 这是一种非常有表现力的方法,可以使用Field1查找BigList元素, BigList元素没有等效的SmallList

var bigListWithoutSmallList = 
    BigList.Where( b => !SmallList.Any( x => x.Field1 == b.Field1 ));

注意:使用classstruct与您的问题无关。

一种解决方案是实现IEquatable<MyStruct>

 class Program
    {
        static void Main(string[] args)
        {
            var smallList = new List<MyStruct>() { new MyStruct
          {
              Field1="1f",
               Field2 ="2f"
          },
          new MyStruct
          {
              Field1="2f",
               Field2 ="22f"
          }};
            var bigList = new List<MyStruct>() { new MyStruct
          {
              Field1="1f",
               Field2 ="2f"
          },
          new MyStruct
          {
              Field1="3 f",
               Field2 ="22f"
          },new MyStruct
          {
              Field1="4f",
               Field2 ="22f"
          } 
            };


              //find the difference 
            var diffList = smallList.Except(bigList);  

        }
        public struct MyStruct:IEquatable<MyStruct>
        {
            public string Field1;
            public string Field2;

            public bool Equals(MyStruct other)
            {
                if (this.Field1==other.Field1 && this.Field2==other.Field2)
                {
                    return true;   
                }
                return false;   
            }
            public override int GetHashCode()
            {
                return Field1.GetHashCode() & Field2.GetHashCode();
            }
       public override bool Equals(object obj)
        {
            return  this.Equals(obj);
        }
        }
    }

结果可能是带有

       new MyStruct
              {
                  Field1="2f",
                   Field2 ="22f"
              }};

有一个名为MoreLINQ的开源库,它提供了一个扩展方法,称为IEnumerable<T> ExceptByExceptBy您的需要。

ExceptBy具有以下签名:

public static IEnumerable<TSource> ExceptBy<TSource, TKey>(
    this IEnumerable<TSource> first, 
    IEnumerable<TSource> second, 
    Func<TSource, TKey> keySelector);

键选择器是将源值映射到用于比较的键值的函数,但是结果仍然是TSource的序列。

在您的情况下,将这样调用:

var Missing = BigList
    .ExceptBy(SmallList, (item => item.fieldToCompareBy)
    .ToList();

与在Where子句中使用ContainsAny相比,此方法具有相当好的性能。 它只需要立即遍历second序列一次,然后就可以懒惰地从第first序列中获取结果流。

如果仅在结构中覆盖Equals,则Except将起作用。 诀窍是您需要在内部将其视为Nullable。

class Program
{
    static void Main(string[] args)
    {
        var smallList = new List<MyStruct>()
        {
            new MyStruct { Field1="1f", Field2 ="2f" },
            new MyStruct { Field1="2f", Field2 ="22f" }
        };

        var bigList = new List<MyStruct>()
        {
            new MyStruct { Field1="1f", Field2 ="2f" },
            new MyStruct { Field1="3f", Field2 ="22f" },
            new MyStruct { Field1="4f", Field2 ="22f" }
        };

        var result = bigList.Except(smallList);

        Console.ReadLine();
    }
}

public struct MyStruct
{
    public string Field1;
    public string Field2;
    public override bool Equals(object obj)
    {
        return Field1 == (obj as Nullable<MyStruct>).Value.Field1;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM