Intersect() 的反面

Posted

技术标签:

【中文标题】Intersect() 的反面【英文标题】:The opposite of Intersect() 【发布时间】:2011-08-02 23:29:24 【问题描述】:

Intersect 可用于查找两个集合之间的匹配项,如下所示:

// Assign two arrays.
int[] array1 =  1, 2, 3 ;
int[] array2 =  2, 3, 4 ;
// Call Intersect extension method.
var intersect = array1.Intersect(array2);
// Write intersection to screen.
foreach (int value in intersect)

    Console.WriteLine(value); // Output: 2, 3

然而我想要实现的恰恰相反,我想列出一个集合中缺少另一个集合的项目

// Assign two arrays.
int[] array1 =  1, 2, 3 ;
int[] array2 =  2, 3, 4 ;
// Call "NonIntersect" extension method.
var intersect = array1.NonIntersect(array2); // I've made up the NonIntersect method
// Write intersection to screen.
foreach (int value in intersect)

    Console.WriteLine(value); // Output: 4

【问题讨论】:

请确认是要输出 4 还是 1 和 4 @oyvind-knobloch-brathen 是的,我只想要 4 附带说明,这种类型的集合称为Symmetric Difference。 从技术上讲,对称差异将导致 [1, 4]。由于 Peter 只想要 array2 中不在 array1 中的元素(即 4),这被称为 Relative Complement(又名集合理论差异) 【参考方案1】:

如前所述,如果你想得到 4 作为结果,你可以这样做:

var nonintersect = array2.Except(array1);

如果您想要真正的不相交(也包括 1 和 4),那么这应该可以解决问题:

var nonintersect = array1.Except(array2).Union( array2.Except(array1));

这不是最高效的解决方案,但对于小型列表,它应该可以正常工作。

【讨论】:

什么是性能更好的解决方案?谢谢! 你可以通过使用两个嵌套的 for 循环更快地完成它,但代码会比这更脏。考虑到可读性,我显然会使用这个变体,因为它很容易阅读。 只是补充一点,如果你有: int[] before = 1, 2, 3 ; int[] after = 2, 3, 3, 4 ;并且您尝试使用 except 来查找自 'before' 以来添加到 'after' 中的内容: var diff = after.Except(before); 'diff' 包含 4,而不是 3,4。即注意重复的元素会给你带来意想不到的结果 这个性能会更好吗? array1.AddRange(array2.Except(array1)); @ØyvindBråthen 谢谢你帮了大忙。【参考方案2】:

你可以使用

a.Except(b).Union(b.Except(a));

或者你可以使用

var difference = new HashSet(a);
difference.SymmetricExceptWith(b);

【讨论】:

SymmetricExceptWith() 的有趣使用,我不会想到那种方法 SymmetricExceptWith 可能是我最喜欢的方法。 我在一个真实的应用程序中比较了两者,其中我有几个列表,每个列表中都有大约 125 个字符串。对于这种大小的列表,使用第一种方法实际上更快,尽管它在半毫秒以下的两种方法中几乎是微不足道的。 如果 BCL 有一个 Linq 扩展方法会很好。这似乎是一个遗漏。 有人对 SymmetricExceptWith 进行基准测试并发现它更快:skylark-software.com/2011/07/linq-and-set-notation.html【参考方案3】:

此代码仅枚举每个序列一次并使用Select(x => x) 隐藏结果以获得干净的Linq 样式扩展方法。因为它使用HashSet<T>,所以如果散列分布良好,它的运行时间是O(n + m)。忽略任一列表中的重复元素。

public static IEnumerable<T> SymmetricExcept<T>(this IEnumerable<T> seq1,
    IEnumerable<T> seq2)

    HashSet<T> hashSet = new HashSet<T>(seq1);
    hashSet.SymmetricExceptWith(seq2);
    return hashSet.Select(x => x);

【讨论】:

我喜欢扩展方法,但我不确定 .Select(x => x)。你不觉得它增加了一些不必要的开销吗?【参考方案4】:

我想你可能正在寻找Except:

Except 运算符产生集合 两个序列的区别。它 只会返回第一个元素 序列中没有出现的 第二。您可以选择提供 你自己的相等比较函数。

查看this link、this link 或 Google,了解更多信息。

【讨论】:

【参考方案5】:

array1.NonIntersect(array2);

Nonintersect 这样的运算符在 Linq 中不存在,您应该这样做

除了 -> 联合 -> 除了

a.except(b).union(b.Except(a));

【讨论】:

【参考方案6】:

我不是 100% 确定您的 NonIntersect 方法应该做什么(关于集合论)- 是吗 B \ A(来自 B 且未出现在 A 中的所有内容)? 如果是,那么您应该可以使用Except 操作(B.Except(A))。

【讨论】:

集合的交集 == A∪B\A∩B【参考方案7】:
/// <summary>
/// Given two list, compare and extract differences
/// http://***.com/questions/5620266/the-opposite-of-intersect
/// </summary>
public class CompareList

    /// <summary>
    /// Returns list of items that are in initial but not in final list.
    /// </summary>
    /// <param name="listA"></param>
    /// <param name="listB"></param>
    /// <returns></returns>
    public static IEnumerable<string> NonIntersect(
        List<string> initial, List<string> final)
    
        //subtracts the content of initial from final
        //assumes that final.length < initial.length
        return initial.Except(final);
    

    /// <summary>
    /// Returns the symmetric difference between the two list.
    /// http://en.wikipedia.org/wiki/Symmetric_difference
    /// </summary>
    /// <param name="initial"></param>
    /// <param name="final"></param>
    /// <returns></returns>
    public static IEnumerable<string> SymmetricDifference(
        List<string> initial, List<string> final)
    
        IEnumerable<string> setA = NonIntersect(final, initial);
        IEnumerable<string> setB = NonIntersect(initial, final);
        // sum and return the two set.
        return setA.Concat(setB);
    

【讨论】:

【参考方案8】:
string left = "411329_SOFT_MAC_GREEN";
string right= "SOFT_MAC_GREEN";

string[] l = left.Split('_');
string[] r = right.Split('_');

string[] distinctLeft = l.Distinct().ToArray();
string[] distinctRight = r.Distinct().ToArray();

var commonWord = l.Except(r, StringComparer.OrdinalIgnoreCase)
string result = String.Join("_",commonWord);
result = "411329"

【讨论】:

以上是关于Intersect() 的反面的主要内容,如果未能解决你的问题,请参考以下文章

php array_intersect() 效率

SQL INTERSECT的用法

php动态array_intersect

MongoDB - 我如何查询 SQL 的“INTERSECT”?

php---array_intersect_assoc

intersect for multiple vectors in R