在单元格和数组上运行的有用函数

这个简单的例子提供了一些解释,我发现自从我开始使用 MATLAB 以来非常有用的一些函数:cellfunarrayfun。我们的想法是获取一个数组或单元类变量,遍历其所有元素并在每个元素上应用专用函数。应用函数可以是匿名的,通常是一种情况,也可以是* .m 文件中定义的任何常规函数。

让我们从一个简单的问题开始,并说我们需要找到给定该文件夹的* .mat 文件列表。对于此示例,首先让我们在当前文件夹中创建一些* .mat 文件:

for n=1:10; save(sprintf('mymatfile%d.mat',n)); end

执行代码后,应该有 10 个扩展名为* .mat 的新文件。如果我们运行命令列出所有* .mat 文件,例如:

mydir = dir('*.mat');

我们应该得到一个 dir 结构元素的数组; MATLAB 应该给出一个类似的输出:

10x1 struct array with fields:
    name
    date
    bytes
    isdir
    datenum

如你所见,此数组的每个元素都是一个包含几个字段的结构。所有信息对于每个文件确实很重要,但在 99%中我对文件名很感兴趣而没有别的。为了从结构数组中提取信息,我曾经创建了一个本地函数,它涉及创建正确大小的时间变量,for 循环,从每个元素中提取名称,并将其保存到创建的变量中。实现完全相同结果的更简单方法是使用上述功能之一:

mydirlist = arrayfun(@(x) x.name, dir('*.mat'), 'UniformOutput', false)
mydirlist = 
    'mymatfile1.mat'
    'mymatfile10.mat'
    'mymatfile2.mat'
    'mymatfile3.mat'
    'mymatfile4.mat'
    'mymatfile5.mat'
    'mymatfile6.mat'
    'mymatfile7.mat'
    'mymatfile8.mat'
    'mymatfile9.mat'

这个功能如何运作?它通常需要两个参数:一个函数句柄作为第一个参数和一个数组。然后,函数将对给定数组的每个元素进行操作。第三和第四个参数是可选的但很重要。如果我们知道输出不是常规输出,则必须将其保存在单元格中。必须指出将 false 设置为 UniformOutput。默认情况下,此函数会尝试返回常规输出,例如数字向量。例如,让我们提取有关每个文件占用多少磁盘空间的信息(以字节为单位):

mydirbytes = arrayfun(@(x) x.bytes, dir('*.mat'))
mydirbytes =
       34560
       34560
       34560
       34560
       34560
       34560
       34560
       34560
       34560
       34560

或千字节:

mydirbytes = arrayfun(@(x) x.bytes/1024, dir('*.mat'))
mydirbytes =
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500

这次输出是 double 的常规向量。UniformOutput 默认设置为 true

cellfun 是一个类似的功能。这个函数和 arrayfun 之间的区别在于 cellfun 对单元类变量进行操作。如果我们希望仅在单元格’mydirlist’中提取文件名列表中的名称,我们只需要按如下方式运行此函数:

mydirnames = cellfun(@(x) x(1:end-4), mydirlist, 'UniformOutput', false)
mydirnames = 
    'mymatfile1'
    'mymatfile10'
    'mymatfile2'
    'mymatfile3'
    'mymatfile4'
    'mymatfile5'
    'mymatfile6'
    'mymatfile7'
    'mymatfile8'
    'mymatfile9'

同样,由于输出不是常规数字向量,因此输出必须保存在单元格变量中。

在下面的示例中,我将两个函数合并为一个,并仅返回没有扩展名的文件名列表:

cellfun(@(x) x(1:end-4), arrayfun(@(x) x.name, dir('*.mat'), 'UniformOutput', false), 'UniformOutput', false)
ans = 
    'mymatfile1'
    'mymatfile10'
    'mymatfile2'
    'mymatfile3'
    'mymatfile4'
    'mymatfile5'
    'mymatfile6'
    'mymatfile7'
    'mymatfile8'
    'mymatfile9'

它很疯狂但很可能因为 arrayfun 返回了一个预期输入 cellfun 的单元格; 对此的一个注意事项是,我们可以通过将 UniformOutput 设置为 false 来强制显式地将任何这些函数返回到单元格变量中。我们总能在单元格中获得结果。我们可能无法在常规向量中获得结果。

还有一个类似的函数在字段上运行一个结构:structfun。我没有特别发现它和其他两个一样有用但在某些情况下它会发光。例如,如果想知道哪些字段是数字或非数字,则以下代码可以给出答案:

structfun(@(x) ischar(x), mydir(1))

dir 结构的第一个和第二个字段是 char 类型。因此,输出是:

 1
 1
 0
 0
 0

此外,输出是 true / false 的逻辑向量。因此,它是常规的,可以保存在矢量中; 不需要使用单元格类。