【问题标题】:Create array from two arrays elements in pairs without loops [duplicate]从两个数组元素成对创建数组,没有循环[重复]
【发布时间】:2015-03-10 19:59:10
【问题描述】:

这里是一个简单的问题。我有数组:

a = [ 600 746 8556 90456 ]
b = [ 684 864 8600 90500 ]

我想得到:

output = [ a(1):b(1) a(2):b(2) a(3):b(3) a(4):b(4) ]

(或者[ a(1):b(1); a(2):b(2); a(3):b(3); a(4):b(4) ],我不在乎)

如果不使用循环,我无法意识到如何做到这一点,但我知道这应该是一种方式。

有什么想法吗?

提前致谢

【问题讨论】:

  • 我看过这个。让我们进行重复狩猎吧! Loren 提供了很多方法:blogs.mathworks.com/loren/2008/10/13/…
  • @knedlsepp 确实,我相信我以前也看到过类似的问题,但它们不是很适合谷歌搜索。
  • 我将寻找答案最广泛的答案并将其重命名为:“向量化冒号 (:) 的概念”。
  • @knedlsepp 实际上有合适的标题对谷歌搜索有很大帮助,所以这是个好主意!
  • @BasSwinckels:找到一个简洁的解决方案,这不是一种很好的认可方式吗? ;-) 就速度而言,它可能会优于循环。

标签: arrays matlab vector vectorization


【解决方案1】:

方法#1

Vectorized 方法与bsxfun 的屏蔽能力 -

%// Get "extents" formed with each pair of "a" and "b" and max extent
ext = b-a
max_ext = max(ext)

%// Extend all a's to max possible extent
allvals = bsxfun(@plus,a,[0:max_ext]')  %//'

%// Get mask of valid extensions and use it to have the final output
mask  = bsxfun(@le,[0:max_ext]',ext)  %//'
out  = allvals(mask).'

方法 #2

此处列出的是一种基于cumsum 的方法,它必须比之前列出的基于bsxfun 的方法和arrayfun based approach in the other answer 具有更高的内存效率和更快的速度。这是代码-

%// Get "extents" formed with each pair of "a" and "b"
ext = b-a;

%// Ignore cases when "a" might be greater than "b"
a = a(ext>=0);
b = b(ext>=0);
ext = b-a;

if numel(ext)>1

    %// Strategically place "differentiated" values from array,a
    idx = ones(sum(ext+1),1);
    idx([1 cumsum(ext(1:end-1)+1)+1]) = [a(1) diff(a)-ext(1:end-1)];

    %// Perform cumulative summation to have the final output
    out = cumsum(idx)

else %// Leftover cases when there are one or no valid boundaries:(a->b)
    out = a:b
end

示例运行 -

>> a
a =
     6    12    43
>> b
b =
     8    17    43
>> out
out =
     6     7     8    12    13    14    15    16    17    43

【讨论】:

  • 使用b-a避免非常大的数字做得很好
  • @LuisMendo 我认为这是唯一的方法。但是,仍然在allvals 我是extending,其中很多人在下一步中被屏蔽了。
  • 想给第二种方法另一个+1。如果 a 可能大于 b,a=a(ext>=0);b=b(ext>=0); 应作为第二行插入。
  • cumsum 版本的出色表现。为了等效于bsxfun 解决方案,我们需要去掉零运行或负运行,例如:a=[1,10]b=[0,11]。 - 编辑:好的,丹尼尔已经找到了解决方案。
  • @Daniel 谢谢,用它编辑过,很好的建议!!
【解决方案2】:

使用arrayfuncell2matanonymous function 的单线:

output = cell2mat(arrayfun(@(start, stop) start:stop, a, b, 'uni', 0))

解释:函数arrayfun 并行迭代向量ab,然后为它们的每一对元素调用匿名函数。匿名函数返回一个可变大小的向量而不是一个标量,因此您需要使用'UniformOutput', false(可以缩写为'uni', 0)使arrayfun 返回一个元胞数组。最后,您使用cell2mat 将元胞数组压缩成一个向量。

快速测试:

>> a = [10, 20, 40];
>> b = [13, 22, 45];
>> output = cell2mat(arrayfun(@(start, stop) start:stop, a, b, 'uni', 0))
output =
    10    11    12    13    20    21    22    40    41    42    43    44    45

【讨论】:

  • 如果您有兴趣:因为我目前正在测试所有解决方案:如果我使用 @colon 而不是 @(start, stop) start:stop,我将获得 5 倍的加速。这使得这几乎与for 循环一样快。对于大型阵列,cumsum 方法的速度大约快 5 倍。 (考虑到arrayfun 的坏名声,这还不算多。)
  • @knedlsepp 我不知道@colon 甚至存在!
  • @LuisMendo:因为这基本上是唯一的用例,我认为没有它你仍然可以生活。 ;-)
  • @knedlsepp 不。既然我知道它的存在,我会尝试找到一种方法将其包含在近期的答案中:-)
猜你喜欢
  • 2021-04-26
  • 1970-01-01
  • 2019-08-28
  • 1970-01-01
  • 2019-10-27
  • 1970-01-01
  • 2023-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多