first
Где выражение технически необязательно, я чувствую, что он делает намерение более ясным.
Если вам нужен более короткий код:
second
Я работаю над самым большим общим фактором и наименьшим общим множественным назначением, и я должен перечислить общие факторы. 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();
Вы ищете что-то вроде этого? Это должно быть очень много 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;
}
}
}
Я написал это расширение для решения проблемы:
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 }
Вот один из способов сделать это. Справедливости ради, он очень похож на ответ Дэвида Б, за исключением того, что он использует соединение для объединения.
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;
Смотри ниже:
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();