【问题标题】:Matlab, alternative to nested for loopMatlab,替代嵌套for循环
【发布时间】:2012-04-15 05:03:21
【问题描述】:

目前我的 .m 文件看起来像这样

 for a = 1 : 47
  for b = a+1 : 48
   for c = b+1 : 49
    for d = c+1 : 50
     fprintf('%d %d %d %d \n',a,b,c,d);
    end
   end
  end

我正在尝试从 1,2,3,...50 生成 4 个元素的集合 即{1,2,3,4},{1,2,3,5},...{1,2,3,50},{1,2,4,5},..{47, 48 , 49, 50}。因此,总共有 C(50,4) 个集合。我想知道是否有比这 4 个嵌套循环更快的替代方案?一组中的顺序不一定按递增顺序。即如果代码生成 {4,1,2,3} 而不是 {1,2,3,4} 就可以了。

【问题讨论】:

  • Matlab 有并行循环。在文档中搜索“parfor”
  • 我尝试用 parfor N = 4 : 50 添加替换 N = 4 : 50 ,但结果速度较慢。
  • parfor 仅在您设置了 matlabpool 时才会并行化,这需要并行计算工具箱。实际的parfor 命令是基本 Matlab 的一部分,因此开发人员可以在没有该工具箱的情况下工作,然后稍后将其折叠到带有其他工具箱的会话中。

标签: matlab for-loop nested


【解决方案1】:

有趣的问题!

枚举所有可能的组合已得到充分研究,并且有许多解决方案。参见例如this SO question。这是一个简单、有效的解决方案,可以使用两个方便的 Matlab 函数 nchoosek 和 arrayfun 来合理选择 N、k:

% test function for benchmarking
foo = @(a, b, c, d) ( a + b + c + d );

% see detailed timings at https://gist.github.com/2295957
tic;
C = nchoosek([1:50], 4);     % all 230,300 4-tuple combinations
result = arrayfun(@(k) foo(C(k,1),C(k,2),C(k,3),C(k,4)), 1:length(C));
toc;

【讨论】:

  • +1,优雅的答案。不过我质疑你的时机。我可以在 6.4 秒内运行您的代码,而原始代码(经过修改以将结果收集到 230300X1 矩阵中)在 5.0 秒内运行。 (R2011a)
  • @Pursuit 受到您的评论的启发,我编写了一个测试带 (gist.github.com/2295957) 以进行更精确的基准测试。这很简单,但证实了我最初的时间已经过去了。新的时序表明(正确计算)嵌套循环是最快的解决方案(在我的 R2011a 设置中,运行时间中位数为 0.1232 秒与 2.62 秒)。这让我很惊讶。
  • 我喜欢一些真实的测试数据。谢谢!我很惊讶你能够达到一个数量级,但我对循环更快并不感到惊讶。 Matlab 对简单循环非常有效,简单循环是最小内存实现。而 arrayfun 调用并不是特别快,并且必须分配大量内存来跟踪 C 中的值。当我进入微优化时,我经常会得到更简单的循环和更少的高级、漂亮的调用。但是,我认为您的回答解决了最初的问题。希望@endeavour90 能接受。
【解决方案2】:

看起来代码的目的可以表述为调用SomeFunction,所有可能的输入都满足以下条件:

  1. A
  2. D
  3. (隐含,A、B、C、D 为整数)

如果是这种情况,您可以通过消除最外层循环使这段代码更快。即,将for N = 1:50 替换为N = 50。实际上,您多次调用相同的组合。例如,将第一行替换为 N = 4:6 会返回以下结果(“*”行重复):

 A     B     C     D
 N=4
 1     2     3     4

 N=5
 1     2     3     4 *
 1     2     3     5
 1     2     4     5
 1     3     4     5
 2     3     4     5

 N=6
 1     2     3     4 *
 1     2     3     5 *
 1     2     3     6
 1     2     4     5 *
 1     2     4     6 
 1     2     5     6
 1     3     4     5 *
 1     3     4     6 
 1     3     5     6
 1     4     5     6
 2     3     4     5 *
 2     3     4     6
 2     3     5     6
 2     4     5     6
 3     4     5     6

【讨论】:

  • 我就是这么想的。移除外循环并替换为 N=50。
  • 好吧,假设 N = 50 我正在寻找从 1,2,3,...50 增加 4 元组的组合的替代方案,而不使用 4 for 循环,即 (1 2 3 4 ), (1 2 3 5),..., (1 2 3 50), (1 2 4 5), ...(47 48 49 50)
  • 我怀疑还有更干净更漂亮的方式。当/如果我想出一个(或者其他人可能会发布一个),我会更新这个答案。我不认为会有更快的方法。
  • 嗨,我改变了问题。希望它更容易理解。谢谢
猜你喜欢
  • 2020-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-10
  • 2022-01-14
  • 1970-01-01
相关资源
最近更新 更多