C# 如何在保留重复项的同时进行整数列表交集?

C# 如何在保留重复项的同时进行整数列表交集?,c#,duplicates,intersection,C#,Duplicates,Intersection,我正在做一个最大公因数和最小公倍数的作业,我必须列出公因数。交集()不起作用,因为它会删除重复项。Contains()不起作用,因为如果它在第二个列表中看到int,它将返回第一个列表中所有匹配的int。有没有一种方法可以进行不明显的交叉 编辑:很抱歉没有提供示例,我的意思是: 如果我有电视机: {1, 2, 2, 2, 3, 3, 4, 5} {1, 1, 2, 2, 3, 3, 3, 4, 4} 我想要输出 {1, 2, 2, 3, 3, 4} ILookup lookup1=list1.

我正在做一个最大公因数和最小公倍数的作业,我必须列出公因数。交集()不起作用,因为它会删除重复项。Contains()不起作用,因为如果它在第二个列表中看到int,它将返回第一个列表中所有匹配的int。有没有一种方法可以进行不明显的交叉

编辑:很抱歉没有提供示例,我的意思是:

如果我有电视机:

{1, 2, 2, 2, 3, 3, 4, 5}
{1, 1, 2, 2, 3, 3, 3, 4, 4}
我想要输出

{1, 2, 2, 3, 3, 4}
ILookup lookup1=list1.ToLookup(i=>i);
ILookup lookup2=list2.ToLookup(i=>i);
int[]结果=
(
从lookup1中的组1
设group2=lookup2[group1.Key]
其中group2.Any()
让smallerGroup=group1.Count()
where表达式在技术上是可选的,我觉得它使意图更加清晰


如果您想要更简洁的代码:

ILookup<int, int> lookup2 = list2.ToLookup(i => i);

int[] result =
(
  from group1 in list1.GroupBy(i => i)
  let group2 = lookup2[group1.Key]
  from i in (group1.Count() < group2.Count() ? group1 : group2)
  select i
).ToArray();
ILookup lookup2=list2.ToLookup(i=>i);
int[]结果=
(
来自list1.GroupBy中的group1(i=>i)
设group2=lookup2[group1.Key]
从i到in(group1.Count()
你在找这样的东西吗?它应该是O(n+m),其中n是第一个
中的项目数,m是第二个
中的项目数

public static IEnumerable<T> Overlap<T>(this IEnumerable<T> first,
    IEnumerable<T> second, IEqualityComparer<T> comparer = null)
{
    // argument checking, optimisations etc removed for brevity

    var dict = new Dictionary<T, int>(comparer);

    foreach (T item in second)
    {
        int hits;
        dict.TryGetValue(item, out hits);
        dict[item] = hits + 1;
    }

    foreach (T item in first)
    {
        int hits;
        dict.TryGetValue(item, out hits);
        if (hits > 0)
        {
            yield return item;
            dict[item] = hits - 1;
        }
    }
}
公共静态IEnumerable重叠(此IEnumerable优先,
IEnumerable秒,IEqualityComparer比较器=null)
{
//为简洁起见,删除了参数检查、优化等
var dict=新字典(比较器);
foreach(第二个项目中的T项)
{
整数命中率;
dict.TryGetValue(项目,超出点击次数);
dict[项目]=点击次数+1;
}
foreach(第一个中的T项)
{
整数命中率;
dict.TryGetValue(项目,超出点击次数);
如果(点击次数>0)
{
收益回报项目;
dict[项目]=点击次数-1;
}
}
}
  • 找到两个列表的交集
  • 按相交项对列表进行分组
  • 加入组,并为每个项目选择最小值(计数)
  • 平铺成一个新的列表
见下文:

var intersect = list1.Intersect(list2).ToList();
var groups1 = list1.Where(e => intersect.Contains(e)).GroupBy(e => e);
var groups2 = list2.Where(e => intersect.Contains(e)).GroupBy(e => e);

var allGroups = groups1.Concat(groups2);

return allGroups.GroupBy(e => e.Key)
    .SelectMany(group => group
        .First(g => g.Count() == group.Min(g1 => g1.Count())))
    .ToList();

这里有一个方法。公平地说,它与davidb的答案非常相似,只是它使用了一个join来进行关联

IEnumerable<Foo> seqA = ...
IEnumerable<Foo> seqB = ...

var result = from aGroup in seqA.GroupBy(x => x)
             join bGroup in seqB.GroupBy(x => x) 
                         on aGroup.Key equals bGroup.Key
             let smallerGroup = aGroup.Count() < bGroup.Count() 
                                ? aGroup : bGroup
             from item in smallerGroup
             select item;
IEnumerable seka=。。。
IEnumerable seqB=。。。
var结果=来自Seka.GroupBy中的aGroup(x=>x)
在seqB.GroupBy中加入bGroup(x=>x)
在aGroup.Key上等于bGroup.Key
让smallerGroup=aGroup.Count()
您可以使用我编写的这个通用扩展,它本质上是一个Linq语句。注意,它使用
Zip
来避免不必要的匹配组的完全枚举

public static IEnumerable<T> Commom<T>(
        this IEnumerable<T> source,
        IEnumerable<T> sequence,
        IEqualityComparer<T> comparer = null)
{
    if (sequence == null)
    {
        return Enumerable.Empty<T>();
    }

    if (comparer == null)
    {
        comparer = EqualityComparer<T>.Default;
    }

    return source.GroupBy(t => t, comparer)
        .Join(
            sequence.GroupBy(t => t, comparer),
            g => g.Key,
            g => g.Key,
            (lg, rg) => lg.Zip(rg, (l, r) => l),
            comparer)
        .SelectMany(g => g);
}

根据需要维护源序列的顺序。

我编写此扩展以解决此问题:

public static IEnumerable<T> Supersect<T>(this IEnumerable<T> a, ICollection<T> b)
              => a.Where(t => b.Remove(t));

如果a是{3,3,3}而b是{3,3},那么您希望输出中有多少个3?2、4或6?我认为下面的答案混淆了问题。正确的问题是“找到两个集合的交集”。问题是,
Intersect
操作符删除重复项-在不删除重复项的情况下解决问题。为什么?这将删除重复项。解释你的逻辑。@JonathanGrynspan当然不会删除两个直接来自交叉点操作的重复项,绝对不会删除重复项!或者你可能想参考集合交叉操作的基本定义。+1我深深地想起了这个问题,我们都回答了这个问题。:)@少校,我的回答避免了完全计算两个匹配组,这必须更好,但是已经晚了三年:-)
new[] {1, 2, 2, 2, 3, 3, 4, 5}.Common(
    new[] {1, 1, 2, 2, 3, 3, 3, 4, 4}).ToArray()
public static IEnumerable<T> Supersect<T>(this IEnumerable<T> a, ICollection<T> b)
              => a.Where(t => b.Remove(t));
var a = new List<int> { 1, 2, 2, 2, 3, 3, 4, 5 };
var b = new List<int> { 1, 1, 2, 2, 3, 3, 3, 4, 4};

var result = a.Supersect(b);
{ 1, 2, 2, 3, 3, 4 }