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

发布于 2024-10-17 17:38:39 字数 320 浏览 4 评论 0原文

我正在做最大公因数和最小公倍数作业,我必须列出公因数。 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}

I'm working on a Greatest Common Factor and Least Common Multiple assignment and I have to list the common factors. Intersection() won't work because that removes duplicates. Contains() won't work because if it sees the int in the second list it returns all matching ints from the first list. Is there a way to do an Intersection that is not Distinct?

edit: sorry for not providing an example, here is what I meant:

if I have the sets:

{1, 2, 2, 2, 3, 3, 4, 5}
{1, 1, 2, 2, 3, 3, 3, 4, 4}

I would want the output

{1, 2, 2, 3, 3, 4}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

一直在等你来 2024-10-24 17:38:39

我写了这个扩展来解决问题:

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

示例:

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 }

I wrote this extension to solve the problem:

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

example:

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);

result:

{ 1, 2, 2, 3, 3, 4 }
蓝咒 2024-10-24 17:38:39
ILookup<int, int> lookup1 = list1.ToLookup(i => i);
ILookup<int, int> lookup2 = list2.ToLookup(i => i);

int[] result =
(
  from group1 in lookup1
  let group2 = lookup2[group1.Key]
  where group2.Any()
  let smallerGroup = group1.Count() < group2.Count() ? group1 : group2
  from i in smallerGroup
  select i
).ToArray();

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<int, int> lookup1 = list1.ToLookup(i => i);
ILookup<int, int> lookup2 = list2.ToLookup(i => i);

int[] result =
(
  from group1 in lookup1
  let group2 = lookup2[group1.Key]
  where group2.Any()
  let smallerGroup = group1.Count() < group2.Count() ? group1 : group2
  from i in smallerGroup
  select i
).ToArray();

The where expression is technically optional, I feel it makes the intent clearer.


If you want more terse code:

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();
寄居者 2024-10-24 17:38:39

您可以使用我为另一个答案编写的通用扩展,它本质上是一个单一的 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);
}

这使得能够

new[] {1, 2, 2, 2, 3, 3, 4, 5}.Common(
    new[] {1, 1, 2, 2, 3, 3, 3, 4, 4}).ToArray()

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

You could use this generic extension I wrote for another answer, it is essentially a single Linq statement. Note that it uses Zip to avoid the needless full enumeration of matched groups.

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);
}

this enables,

new[] {1, 2, 2, 2, 3, 3, 4, 5}.Common(
    new[] {1, 1, 2, 2, 3, 3, 3, 4, 4}).ToArray()

maintaining the order of the source sequence, as desired.

只是在用心讲痛 2024-10-24 17:38:39

您在寻找这样的东西吗?它应该是O(n+m),其中nfirstm中的项目数em> 是 中的项目数。

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;
        }
    }
}

Are you looking for something like this? It should be pretty-much O(n+m), where n is the number of items in first and m is the number of items in second.

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;
        }
    }
}
面犯桃花 2024-10-24 17:38:39

这是一种方法。公平地说,它与 David B 的答案非常相似,只是它使用连接来进行关联。

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;

Here's one way to do it. To be fair, it is very similar to David B's answer except that it uses a join to do the association.

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;
夜深人未静 2024-10-24 17:38:39
  • 找到两个列表的交集。
  • 按相交的项目对列表进行分组
  • 加入组,然后为每个项目选择最小值(计数)
  • 平铺到新列表中。

见下文:

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();
  • Find the intersection of the two lists.
  • Group the lists by the intersecting items
  • Join the groups, and select the Min(Count) for each item
  • Flatten into a new list.

See below:

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文