简体   繁体   English

C#中的通用列表比较

[英]Generic list comparison in C#

I have a method that finds differences between two lists of ints using a dictionary. 我有一种方法,可以使用字典查找两个整数列表之间的差异。 Essentially the code loops the first list, adding each int to the dictionary and setting (to 1 where not already present)/incrementing the value. 本质上,代码循环了第一个列表,将每个int添加到字典中并设置(如果不存在,则设置为1)/递增值。 It then loops the second list setting (to -1 where not already present)/decrementing the value. 然后,它循环第二个列表设置(如果不存在则循环为-1)/减小该值。

Once it has looped both lists you end up with a dictionary where keys with values = 0 indicate a match, keys with values >=1 indicate presence only in the first list and values <=-1 indicate presence only in the second list. 一旦两个列表都循环,您将得到一个词典,其中值= 0的键表示匹配,值> = 1的键仅表示在第一个列表中,而值<=-1表示仅在第二个列表中。

Firstly, is this a sensible implementation? 首先,这是明智的实现吗?

Secondly, I would like to make it more generic, at the moment it can only handle int based lists. 其次,我想使其更通用,目前它只能处理基于int的列表。 I'd like something that could handle any object where the caller could potentially define the comparison logic... 我想要可以处理调用方可能定义比较逻辑的任何对象的东西...

    public static Dictionary<int, int> CompareLists(List<int> listA, List<int> listB)
    {
        // 0        Match
        // <= -1    listB only
        // >= 1     listA only
        var recTable = new Dictionary<int, int>();

        foreach (int value in listA)
        {
            if (recTable.ContainsKey(value))
                recTable[value]++;
            else
                recTable[value] = 1;
        }

        foreach (int value in listB)
        {
            if (recTable.ContainsKey(value))
                recTable[value]--;
            else
                recTable[value] = -1;
        }

        return recTable;

    }

Thanks in advance! 提前致谢!

In response to: "It won't work properly if to example you have same value appears twice in listA and once in listB, result will be positive, which say "listA only" in your comments." 回应: “例如,如果您具有相同的值在listA中出现两次,而在listB中出现一次,则结果将是肯定的,在您的注释中显示“仅listA”。

Let me clarify; 让我澄清一下; if a value appears twice in listA it should also appear twice in listB - So if a value is in listA twice and once in listB, I don't care which one from listA it picks to match, as long as the one non-reconciling item is reported correctly. 如果一个值在listA中出现两次,那么它也应该在listB中出现两次-因此,如果一个值在listA中出现两次,并且在listB中出现一次,那么我不在乎它选择从listA中匹配哪个,只要一个不协调项目已正确报告。

Imagine the use-case where you are trying to reconcile lots of payment amounts between two files, it's entirely feasible to have repeating amounts but it doesn't really matter which of the duplicates are matched as long as the non-reconciling values are reported. 想象一下用例,您试图在两个文件之间协调很多付款金额,重复金额是完全可行的,但是只要报告了未对帐的值,则匹配哪个重复项并不重要。

To answer your second question, here's how to make it more generic: 为了回答您的第二个问题,以下是如何使其更通用的方法:

public static Dictionary<T, int> CompareLists<T>(IEnumerable<T> listA, 
    IEnumerable<T> listB, IEqualityComparer<T> comp)
{
    var recTable = new Dictionary<T, int>(comp);

    foreach (var value in listA)
    {
        if (recTable.ContainsKey(value))
            recTable[value]++;
        else
            recTable[value] = 1;
    }

    foreach (var value in listB)
    {
        if (recTable.ContainsKey(value))
            recTable[value]--;
        else
            recTable[value] = -1;
    }

    return recTable;
}

This is more generic because: 这是更通用的,因为:

  • I pass in the type T instead of an int. 我传入类型T而不是int。
  • I use IEnumerables instead of Lists. 我使用IEnumerables而不是列表。
  • I pass in an IEqualityComparer and pass it to the Dictionary constructor which needs to use it. 我传入IEqualityComparer并将其传递给需要使用它的Dictionary构造函数。
  • I use var in the foreach loops instead of int . 我在foreach循环中使用var ,而不是int You can also use T . 您也可以使用T

You call this code like this: 您可以这样调用此代码:

static void Main()
{
    int[] arr1 = { 1, 2, 3 };
    int[] arr2 = { 3, 2, 1 };

    var obj = CompareLists(arr1, arr2, EqualityComparer<int>.Default);

    Console.ReadLine();
}

Here's an example of implementing IEqualityComparer. 这是实现IEqualityComparer的示例。 This treats all odd ints as equal and all even ints as equal: 这会将所有奇数整数视为相等,并将所有偶数整数视为相等:

public class MyEq : IEqualityComparer<int>
{
    public bool Equals(int x, int y)
    {
        return (x % 2) == (y % 2);
    }

    public int GetHashCode(int obj)
    {
        return (obj % 2).GetHashCode();
    }
}

FullOuterJoin as found here: LINQ - Full Outer Join FullOuterJoin,位于此处:LINQ- 完整外部联接

public static Dictionary<int, int> CompareLists(List<int> listA, List<int> listB)
{
  return listA.FullOuterJoin(listB,
    a=>a, // What to compare from ListA
    b=>b, // What to compare from ListB
    (a,b,key)=>
      new {key=key,value=0}, // What to return if found in both
      new {key=key,value=-1},// What to return if found only in A
      new {key=key,value=1}) // What to return if found only in B
    .ToDictionary(a=>a.key,a=>a.value); // Only because you want a dictionary
}

You can do this using Generics: 您可以使用泛型执行此操作:

public static Dictionary<T, int> CompareLists<T>(List<T> listA, List<T> listB)
{
    // 0        Match
    // <= -1    listB only
    // >= 1     listA only
    var recTable = new Dictionary<T, int>();

    foreach (T value in listA)
    {
        if (recTable.ContainsKey(value))
            recTable[value]++;
        else
            recTable[value] = 1;
    }

    foreach (T value in listB)
    {
        if (recTable.ContainsKey(value))
            recTable[value]--;
        else
            recTable[value] = -1;
    }

    return recTable;

}

These are my two cents: 这是我的两分钱:

public static Dictionary<T, int> CompareLists<T>(List<T> left, List<T> right, IEqualityComparer<T> comparer)
{
    Dictionary<T, int> result = left.ToDictionary(l => l, l => right.Any(r => comparer.Equals(l, r)) ? 0 : -1);
    foreach (T r in right.Where(t => result.Keys.All(k => !comparer.Equals(k, t))))
        result[r] = 1;
    return result;
}

The method takes List s of any type T and an IEqualityComparer for that type T . 该方法以List的任何类型的第TIEqualityComparer为该类型T It then at first generates a dictionary of those elements contained in the "left" List , thereby checking if they are also in the "right" List and setting the value accordingly. 然后,它首先生成包含在“左侧” List的那些元素的字典,从而检查它们是否也位于“右侧” List并相应地设置值。

The second step adds the elements that are only contained in the "right" List with value 1 . 第二步添加仅包含在值为1的“正确” List的元素。

If this is a sensible implementation depends on what you are trying to achieve with it. 如果这是一个明智的实现,则取决于您要尝试实现的目标。 I think it's a short but still readable one, relying on proper implementation of the LINQ methods. 我认为这是一个简短但仍易读的方法,它依赖于LINQ方法的正确实现。 Though there might be faster possibilities one could think about if this is for really big lists or an very often called method. 尽管可能会有更快的可能性,但人们可能会想这是否用于大型列表或通常被称为方法。

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

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