C# 高效的.NET对处理
以下代码允许您处理所有可能的对象对(其中DoSomething(a,b)等同于DoSomething(b,a),您不想同时执行这两个操作,并且您永远不需要DoSomething(a,a)):C# 高效的.NET对处理,c#,arrays,list,collections,generics,C#,Arrays,List,Collections,Generics,以下代码允许您处理所有可能的对象对(其中DoSomething(a,b)等同于DoSomething(b,a),您不想同时执行这两个操作,并且您永远不需要DoSomething(a,a)): void MyMethod(虚构[]myArray) { 对于(int j=0;j
void MyMethod(虚构[]myArray)
{
对于(int j=0;j<(myArray.Length-1);+j)
{
对于(int k=j+1;k
我知道这大约是n*n/2次操作
如果使用列表而不是数组,是否有同样有效的方法来处理所有可能的对?(特别是一个解决方案,我不必在内部循环中旋转已经完成的元素)。也许是使用了枚举器
数组不好,因为我事先不知道需要多少神话(可能是0,可能永远不会超过1000)。对于这种特殊用途,是否有比列表
更好的集合?我不需要排序,我只创建新集合、清除现有集合、添加到集合、枚举集合或如上所述处理配对。无论我使用什么收藏,我都可能需要100到10000个,所以创建/保存它们的成本不会太高
假设DoSomething()正在对移动对象执行碰撞检测和响应。在这种情况下,总是有机会记忆算法,但如果不了解有关DoSomething的更多详细信息,则无法说出可以做什么
例如,假设DoSomething
如下所示:
void DoSomething(MyThing arg1, MyThing arg2)
{
// Let's assume MyThing.Value is an int
// and you want to print the product of both values
Console.WriteLine(arg1.Value * arg2.Value);
}
在本例中,我们可以跟踪在内存中传递了哪些参数,并且只为我们尚未看到的参数组合调用该方法。当然,这只适用于需要大量执行时间来保证记忆开销的DoSomething
实现。在这种情况下,总是有机会记忆算法,但如果不了解DoSomething
的更多细节,就不可能说出可能发生的情况完成了
例如,假设DoSomething
如下所示:
void DoSomething(MyThing arg1, MyThing arg2)
{
// Let's assume MyThing.Value is an int
// and you want to print the product of both values
Console.WriteLine(arg1.Value * arg2.Value);
}
在本例中,我们可以跟踪在内存中传递了哪些参数,并且只为我们尚未看到的参数组合调用该方法。当然,这仅适用于需要大量执行时间来保证内存开销的DoSomething
实现。列表
将正常工作。您只需将方法签名中的MyThing[]
替换为List
如果您正在寻找一种可用于枚举的解决方案,那么就为了它:
void MyMethod<T>(IEnumerable<T> myThings, Action<T, T> action)
{
int index = 0;
foreach (var a in myThings)
foreach (var b in myThings.Skip(++index))
action(a, b);
}
void MyMethod(IEnumerable myThings,Action-Action)
{
int指数=0;
foreach(神话中的var a)
foreach(myThings.Skip(++索引)中的变量b)
行动(a、b);
}
请注意,这会稍微慢一点,因为Skip
实际上会迭代跳过的元素。这可能会抵消您在接近列表末尾时从内存缓存中获得的任何好处,当然这会浪费时间丢弃前N个元素。list
可以正常工作。您只需将方法签名中的MyThing[]
替换为List
如果您正在寻找一种可用于枚举的解决方案,那么就为了它:
void MyMethod<T>(IEnumerable<T> myThings, Action<T, T> action)
{
int index = 0;
foreach (var a in myThings)
foreach (var b in myThings.Skip(++index))
action(a, b);
}
void MyMethod(IEnumerable myThings,Action-Action)
{
int指数=0;
foreach(神话中的var a)
foreach(myThings.Skip(++索引)中的变量b)
行动(a、b);
}
请注意,这会稍微慢一点,因为Skip
实际上会迭代跳过的元素。当您接近列表末尾时,这可能会抵消您从内存缓存中获得的任何好处,当然,丢弃前N个元素会浪费时间。N个项目的唯一组合的数量是N/(2!(N-2)!=N(N-1)/2~=O(N^2)。要对列表中两个项目的每一个组合执行一个操作,其复杂性是无法降低的
就要使用的集合而言,一个列表将直接插入到您拥有数组的位置,只需进行一次更改;列表使用Count属性来确定基数,而不是长度
至于更优雅的As和Bs组合方式,Linq确实有一些优势:
var combinations =
from a in myThings.Reverse()
from b in myThings.TakeWhile(x=>x!=a)
select new {a,b};
foreach(var combo in combinations)
DoSomething(combo.a, combo.b);
这仍然会比您原来的算法慢,但我认为它会比cdhowie的算法快一点,因为它将只遍历N个额外的项(以创建Reverse()枚举),而不是跳过N(N-1)正如cdhowie的内部foreach最终所做的那样。每次取2个的N个项目的唯一组合的数量是N/(2!(N-2)!=N(N-1)/2~=O(N^2)。要对列表中两个项目的每一个组合执行一个操作,其复杂性是无法降低的
就要使用的集合而言,一个列表将直接插入到您拥有数组的位置,只需进行一次更改;列表使用Count属性来确定基数,而不是长度
至于更优雅的As和Bs组合方式,Linq确实有一些优势:
var combinations =
from a in myThings.Reverse()
from b in myThings.TakeWhile(x=>x!=a)
select new {a,b};
foreach(var combo in combinations)
DoSomething(combo.a, combo.b);
这仍然会比您原来的算法慢,但我认为它会比cdhowie的算法快一点,因为它将只遍历N个额外的项(以创建Reverse()枚举),而不是像cdhowie的内部foreach那样跳过N(N-1)
有没有同样有效的方法
处理所有可能的对,如果
使用列表而不是
阵列
List
只是一个围绕T[]
的花式包装,当超出列表容量时,它会偶尔调整大小
你的算法已经是最优的了。如果要将其与列表一起使用,只需更改declar即可