使用Linq比较包含重复信息的List<String>

3
为了比较两个List<String>并提取它们的差异,我使用Linq的Except
例如:
假设我想使用Linq比较以下两个列表是否相等:
List1 = "0,1,2,2,3"
List2 = "0,1,2,3"

List<string> differences1 = List1.Except(List2).ToList();
List<string> differences2 = List2.Except(List1).ToList();
differences1differences2不会包含任何项目,因为2存在于两个列表中,但两个列表并不相等。我想要能够提取列表之间的所有差异,包括一个列表具有而另一个列表没有的重复信息。
如何最好地提取两个List<string>对象之间的所有差异?

你尝试过使用Distinct()方法来去除重复项并比较结果列表吗? - semao
你应该真正包含相同的输入/输出。 - Servy
编辑后我有点困惑。你说你希望“0,1,2,2,3”和“0,1,2,3”相等,但又想知道它们的不同之处。嗯? - Becuzz
@Becuzz 不,List1和List2应该是相等的,这就是为什么我要比较它们进行验证的原因。如果它们不同(包括其中一个具有重复项),那么我想知道它们为什么不同。如果我的表述不够清晰,我很抱歉。不过,我不确定这是否值得被投下反对票... - TestK
5个回答

5
所需的是作用于包裹而不是集合的"Except"。 如果一个序列有两个项目的副本,您减去一个只有一个副本的集合,应该还剩下一个副本,而不是在执行减法之前将所有序列减少为不同的集合,就像“Except”那样。
这使得处理稍微不太优雅,但仍然不可怕。 您只需要使用将项目映射到副本数量的字典来代替HashSet来表示另一个集合。 然后对于每个项目,如果它在字典中,则从计数中删除一个并且不进行产出,如果不在字典中,则应该产出它。
public static IEnumerable<T> BagDifference<T>(IEnumerable<T> first
    , IEnumerable<T> second)
{
    var dictionary = second.GroupBy(x => x)
        .ToDictionary(group => group.Key, group => group.Count());

    foreach (var item in first)
    {
        int count;
        if (dictionary.TryGetValue(item, out count))
        {
            if (count - 1 == 0)
                dictionary.Remove(item);
            else
                dictionary[item] = count - 1;
        }
        else
            yield return item;
    }
}

太棒了!这正是我在寻找的。非常感谢你! - TestK
@TestK,你的问题仍然不太清楚;你应该编辑它以澄清。 - Servy
@TestK,它并没有,尽管比以前好了一些。正如我之前说过的,你真的应该有一些示例输入/输出 - Servy

0
您可以按键分组,然后使用Except()比较这些组。
它会像这样(未经测试可能有错别字):
var groupList1 = List1.GroupBy(x => x).ToList();
var groupList2 = List2.GroupBy(x => x).ToList();

var differences1 = groupList1.Except(groupList2).ToList();
var differences2 = groupList2.Except(groupList1).ToList();

0
你可以在比较之前对列表调用.Distinct()方法:
List<string> differences1 = List1.Distinct().Except(List2).ToList();
List<string> differences2 = List2.Distinct().Except(List1).ToList();

1
在使用Except之前调用Distinct没有意义;Except本身会删除重复项。 - Servy

0
你可以使用 Distinct 来消除重复项,然后进行比较。
var distinctList1 = List1.Distinct().ToList();
var distinctList2 = List2.Distinct().ToList();

var differences1 = distinctList1.Except(distinctList2).ToList();
var differences2 = distinctList2.Except(distinctList1).ToList();

在使用Except之前调用Distinct没有意义;Except本身会删除重复项。 - Servy

0
你可以创建列表的副本,然后删除存在于另一个列表中的所有内容:
var diff1 = list1.ToList();
var diff2 = list2.ToList();
diff1.RemoveAll(diff2.Remove);

  1. 这会改变两个集合,而不仅仅是确定它们之间的差异。
  2. 这将表现得非常糟糕,因为从列表中搜索并删除项目并不便宜。
- Servy
性能确实不好!但这并不总是问题。有一个简单的解决方案可以得到差异。 - erikH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接