从另一个数组中移除一个数组的有效算法
本文关键字:数组 一个 有效 算法 另一个 | 更新日期: 2023-09-27 18:08:51
我想知道是否有人知道更好(如更快)的算法/解决方案来解决我的问题:
在我的程序中,我有一个单元数组,我想从中删除包含在另一个单元数组中的项。但是,我不能使用集合的并集,因为我需要保留重复的值。解释得很糟糕,但这个例子应该会让它更清楚一些:
uint[] array_1 = new uint[7] { 1, 1, 1, 2, 3, 4, 4};
uint[] array_2 = new uint[4] { 1, 2, 3, 4 };
uint[] result = array_1 .RemoveRange(array_2);
// result should be: { 1, 1, 4 }
这是我目前最好的主意;但是它相当慢:
public static uint[] RemoveRange(this uint[] source_array, uint[] entries_to_remove)
{
int current_source_length = source_array.Length;
for (int i = 0; i < entries_to_remove.Length; i++)
{
for (int j = 0; j < current_source_length; j++)
{
if (entries_to_remove[i] == source_array[j])
{
// Shifts the entries in the source_array.
Buffer.BlockCopy(source_array, (j + 1)* 4 , source_array, j * 4, (current_source_length - j) * 4);
current_source_length--;
break;
}
}
}
uint[] new_array = new uint[current_source_length];
Buffer.BlockCopy(source_array, 0, new_array, 0, current_source_length * 4);
return new_array;
}
所以,有人能想出一个更聪明的方法来实现我想要的吗?谢谢!
如果使用Dictionary<uint,int>
使用整数数字作为键,并将数字出现的次数作为值呢?
var source = new Dictionary<uint,int>();
source.Add(1,3);
source.Add(2,1);
source.Add(3,1);
source.Add(4,2);
var remove = new uint[]{ 1, 2, 3, 4 };
for (int i = 0; i<remove.Length; i++) {
int occurences;
if (source.TryGet(remove[i], out occurences)) {
if (occurences>1) {
source[remove[i]] = occurences-1;
} else {
source.Remove(remove[i]);
}
}
}
这将做你想要的,据我所知,他们的关键是引用计数的出现次数,然后使用剩余的引用计数(如果> 0)作为一个数字必须发出的次数:
public static uint[] RemoveRange(this uint[] source_array, uint[] entries_to_remove)
{
var referenceCount = new Dictionary<uint, int>();
foreach (uint n in source_array)
{
if (!referenceCount.ContainsKey(n))
referenceCount[n] = 1;
else
referenceCount[n]++;
}
foreach (uint n in entries_to_remove)
{
if (referenceCount.ContainsKey(n))
referenceCount[n]--;
}
return referenceCount.Where(x => x.Value > 0)
.Select(x => Enumerable.Repeat(x.Key, x.Value))
.SelectMany( x => x)
.ToArray();
}
EDIT:这对您没有帮助,因为您希望保留副本。
我把它留在这里给那些不想要副本的人。
从第二个列表创建一个HashSet<T>
,然后用哈希集的Contains
方法调用List<T>.RemoveAll
。
var unwanted = new HashSet<uint(...);
list.RemoveAll(unwanted.Contains);
如果你不想就地删除它们,你可以使用LINQ:
list.Except(unwanted);
Except
将构建两个哈希集并每次返回一个项目(延迟执行)0
如果数组未排序,则对其排序。初始化3个索引为0。"s"(源)和"d"(dest)索引大数组A,"r"索引"toRemove"数组b。
While r<B.length,
While B[r] > A[s], A[d++]= A[s++].
If B[r]==A[s], s++.
r++.
Endwhile.
While s<A.length, A[d++]= A[s++].
A.length = d.
这不需要额外的空间,并且运行时间为O(N),(如果它们最初未排序,则运行时间为nlgn),与原始解决方案的N^2 I相比。
你可以尝试在这里使用Linq,
var resultarray = array1.Except(array2);