Как выполнять перекрестку целочисленного списка при сохранении дубликатов?

Я работаю над самым большим общим фактором и наименьшим общим множественным назначением, и я должен перечислить общие факторы. Intersection () не будет работать, потому что удаляет дубликаты. Содержит () не будет работать, потому что если он видит int в { 1 , 2 , 2 , 2 , 3 , 3 , 4 , 5 } { 1 , 1 , 2 , 2 , 3 , 3 , 3 , 4 , 4 }, он возвращает все подходящие ints из { 1 , 2 , 2 , 3 , 3 , 4 } . Есть ли способ сделать пересечение, которое не отличается?

Редактировать: извините за не предоставление примера, вот что я имел в виду:

если у меня есть наборы:

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

Я бы хотел, чтобы результат

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

c#,duplicates,intersection,

9

Ответов: 6


7 принят
first

Где выражение технически необязательно, я чувствую, что он делает намерение более ясным.


Если вам нужен более короткий код:

second

1

Вы ищете что-то вроде этого? Это должно быть очень много O (n + m) , где n - количество элементов in, firstа m - количество элементов в 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;
        }
    }
}

1

Я написал это расширение для решения проблемы:

public static IEnumerable<T> Supersect<T>(this IEnumerable<T> a, List<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 }

0

Вот один из способов сделать это. Справедливости ради, он очень похож на ответ Дэвида Б, за исключением того, что он использует соединение для объединения.

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;

0
  • Найдите пересечение двух списков.
  • Группируйте списки по пересекающимся элементам
  • Присоединитесь к группам и выберите Min (Count) для каждого элемента
  • Сгладьте в новый список.

Смотри ниже:

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();
C #, дубликаты, пересечение,
Похожие вопросы