我想知道是否有人知道更好(如更快)的算法/解决方案来解决我的问题:
在我的程序中,我有一个uint数组,我想从中删除另一个uint数组中包含的条目。但是,我不能使用集合的并集,因为我需要保留重复的值。措辞严厉的解释,但这个例子应该让它更清楚:
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;
}
再说一次,有人能想出一个更聪明的方法来实现我的目标吗?
谢谢!
答案 0 :(得分:2)
使用uint编号作为密钥使用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]);
}
}
}
答案 1 :(得分:1)
根据我的理解,这可以做你想要的,它们的关键是引用次数的引用计数,然后使用剩余的引用计数(如果> 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();
}
答案 2 :(得分:0)
编辑:这对您没有帮助,因为您想保留重复项 我将它留在这里,供那些不想重复的人使用。
从第二个列表中创建HashSet<T>
,然后使用哈希集的List<T>.RemoveAll
方法调用Contains
。
var unwanted = new HashSet<uint(...);
list.RemoveAll(unwanted.Contains);
如果您不想就地删除它们,可以使用LINQ:
list.Except(unwanted);
Except
将构建两个哈希集并一次返回一个项目(延迟执行0
答案 3 :(得分: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)中运行(或者如果它们最初未排序则运行N lg N),与原始解决方案的N ^ 2 I相比。
答案 4 :(得分:-1)
您可以尝试在这里使用Linq,
var resultarray = array1.Except(array2);