简体   繁体   English

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

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

This is my first post. 这是我的第一篇文章。 I'm fairly new in c# and I'm trying to use lists of a struct type. 我在C#中相当陌生,并且正在尝试使用结构类型的列表。

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

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

So far, everything I've done used a known type (eg string) but for the lists in the example above, I cannot use any of the functions with a positive result. 到目前为止,我所做的一切都使用了已知的类型(例如,字符串),但是对于上面示例中的列表,我无法使用任何具有肯定结果的函数。

At moment, the idea is to get the differences between two lists that use that struct type (List). 目前,其想法是获得使用该结构类型(列表)的两个列表之间的差异。 The BigList will always have more items than the Small list and the idea is to find all items in the SmalList which are not existing in the BigList, considering the Field1. BigList将始终具有比Small列表更多的项目,其想法是考虑到Field1,在SmalList中查找BigList中不存在的所有项目。 Ideally, the result could be a list of the same type (List). 理想情况下,结果可以是相同类型的列表(列表)。

Is this possible? 这可能吗? I've tried some examples I've found in stackoverflow but couldn't find many examples that use lists of structs, and the ones I've tried didn't work. 我已经尝试了一些在stackoverflow中找到的示例,但是找不到许多使用结构列表的示例,而我尝试过的示例却无效。

One example that worked fine with a list of strings: 一个适用于字符串列表的示例:

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

could be a solution, but I need to look at one field (Field1 of the struct) not just a simple string. 可能是一个解决方案,但我需要查看一个字段(结构的Field1),而不仅仅是一个简单的字符串。

Cannot have positive results using .Sort or .Contains for those type of lists (looking specifically to one field of the struct eg List). 对于这些类型的列表,使用.Sort或.Contains不能产生肯定的结果(专门查看结构的一个字段,例如List)。

Can someone help me? 有人能帮我吗? That would be great! 那很好啊!

Thanks in advance. 提前致谢。 Regards, 问候,

As other said, the use of the struct in your example, especially since you're new to C# is probably more of a mistake than a real good idea. 就像其他人所说的,在您的示例中使用struct尤其是由于您是C#的新手,可能不是真正的好主意,而是更多的错误。 I suggest you replace your struct with a class. 我建议您用一个类替换您的结构。

The issue you're facing is because since you're using a type that you have defined yourself, the comparison won't work, or at least won't work as you expect it to work. 您面临的问题是,因为您使用的是自己定义的类型,所以比较将无法正常工作,或者至少无法正常工作。

It won't know how to compare two objects and will, in the case of classes, verify if it's the same object and in case of structs either do a byte-to-byte comparison (if the struct doesn't contain reference types) or compare that the references it contains are the same (if the struct contains reference types). 它不会知道如何比较两个对象,如果是类,则将验证它是否是同一对象,如果是结构,则将进行字节对字节的比较(如果该结构不包含引用类型)或比较它包含的引用是否相同(如果结构包含引用类型)。

What you need to do to make everything work correctly is to override the Equals method in your class. 使一切正常工作所需要做的是重写类中的Equals方法。 See this MSDN article to get started on this: https://msdn.microsoft.com/en-us/library/336aedhh(v=vs.100).aspx . 请参阅此MSDN文章以开始使用它: https : //msdn.microsoft.com/zh-cn/library/336aedhh(v=vs.100).aspx

Alternatively, you can implement the IEqualityComparer for your type. 另外,您可以为您的类型实现IEqualityComparer。 It's especially useful if you don't have access to the class implementation. 如果您无权访问类实现,则它特别有用。 Check this MSDN article to do so: https://msdn.microsoft.com/en-us/library/bb300779(v=vs.110).aspx 检查此MSDN文章以执行此操作: https : //msdn.microsoft.com/zh-cn/library/bb300779(v=vs.110).aspx

There are many ways to solve this problem. 有很多方法可以解决此问题。 Here is a quite expressive way to find elements of BigList that don't have equivalents SmallList using Field1 . 这是一种非常有表现力的方法,可以使用Field1查找BigList元素, BigList元素没有等效的SmallList

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

NOTE: Using a class or struct is not relevant really for your problem. 注意:使用classstruct与您的问题无关。

one solution could be to implement IEquatable<MyStruct> 一种解决方案是实现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);
        }
        }
    }

The result could be the struct with 结果可能是带有

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

There is an open source library called MoreLINQ that provides an extension method called ExceptBy for IEnumerable<T> that can do what you need. 有一个名为MoreLINQ的开源库,它提供了一个扩展方法,称为IEnumerable<T> ExceptByExceptBy您的需要。

ExceptBy has the following signature: ExceptBy具有以下签名:

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

The key selector is a function that maps source values to key values which are used for the comparison, but the result is still a sequence of TSource . 键选择器是将源值映射到用于比较的键值的函数,但是结果仍然是TSource的序列。

In your case it would be invoked like this: 在您的情况下,将这样调用:

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

This method has pretty good performance compared to using Contains or Any inside a Where clause. 与在Where子句中使用ContainsAny相比,此方法具有相当好的性能。 It only has to iterate through the second sequence once immediately, and streams results from the first sequence lazily. 它只需要立即遍历second序列一次,然后就可以懒惰地从第first序列中获取结果流。

Except will work if you just override Equals in the struct. 如果仅在结构中覆盖Equals,则Except将起作用。 The trick is you need to treat it as Nullable internally. 诀窍是您需要在内部将其视为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