如何在octave / matlab中“映射”?

时间:2014-10-10 18:34:47

标签: matlab function map octave

这里有一点八度代码

>> [4,5]([1,2,1])
ans =

   4   5   4

我称之为在矢量[1,2,1]上映射函数1-> 4,2-> 5。

但我想要做的地图是在非常长的矢量上0-> 1,25-> 2,240-> 9,NaN-> 0。

如果向量中除了0,25,240,NaN之外还有任何值,我也会喜欢炸弹。

我可以看到各种方法来实现这一点,它们都不优雅,并且想知道是否有一种惯用的表达方式。

3 个答案:

答案 0 :(得分:2)

以下代码可能不够优雅,但它至少是矢量化的。

vector = [0, 25, 240, NaN, 0, 25, 240, NaN];
old_value = [0, 25, 240, NaN];
new_value = [1,  2,   9,   0];
assert(size_equal(old_value, new_value))
total_mask = false;
for idx = 1:numel(old_value)
    if isnan(old_value(idx))
        partial_mask = isnan(vector);
    else
        partial_mask = vector == old_value(idx);
    endif
    vector(partial_mask) = new_value(idx);
    total_mask |= partial_mask;
endfor
assert(all(total_mask), "some values were unexpected")
vector

给出了

    1   2   9   0   1   2   9   0

如果某个值不在old_values中,则会产生错误。

编辑[更紧凑,但内存更多而且速度更快]:

vector = [0, 25, 240, NaN, 0, 25, 240, NaN];
old_values = [0, 25, 240, NaN];
new_values = [1,  2,   9,   0];
mask__ = vector == old_values(:);
mask__(isnan(old_values), :) = isnan(vector);
assert(all(any(mask__, 1)), "some values were unexpected")
vector = cellfun(@(mask_) new_values(mask_), num2cell(mask__, 1))

答案 1 :(得分:2)

如果你可以使用MATLAB,我建议你使用containers.Map范例,它本质上是一个执行键/值查找的关联数组。如果你输入一个不属于字典的值,它也会吐出错误。因此,您只需为映射中的每个元素提供输入/输出关系。输入是所谓的键,输出是所谓的值。

完成后,使用values函数向字典/关联数组中提供输入值的单元格数组,然后在完成后将此单元格数组转换回数字向量。从输入/输出对来判断,您希望输入为double,输出也为double。但是,containers.Map的问题是NaN不能用作密钥。因此,解决方法是将输入数值向量中的每个元素转换为字符键的单元格数组,并将输出定义为字符值的单元格数组。

我们可以使用arrayfun实现此目的,str2double对数组中的每个值执行操作。这非常类似于for循环,但特别之处在于,如果将uni标志指定为0,则每个对应元素的输出将转换为字符串。然后使用这些单元格字符数组创建字典。现在,要对输入进行映射,您还必须将这些转换为字符的单元格数组,然后使用values获取相应的输出,然后使用{{3}}进行转换每个输出单元格元素返回并将其放入数字数组中。

因此,借用huntj的样本输入,这就是你必须要做的事情:

%// Input-Output relationships
in = [0,25,240,NaN];
out = [1,2,9,0];

%// Test inputs
vector = [0, 25, 240, NaN, 0, 25, 240, NaN];

% // For declaring our dictionary
in_cell = arrayfun(@num2str, in, 'uni', 0);
out_cell = arrayfun(@num2str, out, 'uni', 0);

% // Input test into dictionary
vector_cell = arrayfun(@num2str, vector, 'uni', 0);

% // Create dictionary
dict = containers.Map(in_cell, out_cell);

% // Put in inputs to be mapped
output_cell = values(dict,vector_cell);

% // Convert back to numeric array
output = str2double(output_cell);

这是我使用上面的代码得到的,我们的最终输出存储在output

output =

     1     2     9     0     1     2     9     0

答案 2 :(得分:1)

这可以通过逻辑索引轻松完成。使用huntj的起始载体:

allowed = [0, 25, 240];
v = [0; 25; 240; NaN; 0; 25; 240; NaN];

notAllowed = not(any(bsxfun(@eq,v,allowed),2));
notNaN     = not(isnan(v));
if any(notAllowed & notNaN)
    error('Illegal entry');
end

v( v == 0   ) = 1;
v( v == 25  ) = 2;
v( v == 240 ) = 9;
v( isnan(v) ) = 0;

为了使bsxfun()起作用,v需要是列向量。 NaN表中未包含allowed,因为NaN == NaN始终为false。