【问题标题】:Do MATLAB tables remove the need for dictionaries?MATLAB 表是否不再需要字典?
【发布时间】:2019-05-27 06:36:13
【问题描述】:

MATLAB tables 允许您使用行名称(例如 MyTable.FourthColumn('SecondRowName'))索引到任何列/字段。与此相比,字典 (containers.Map) 看起来很原始,例如,它充当 1 列表的角色。它还有自己的专用语法,这会减慢对如何编码的思考。

我开始认为我可以忘记使用字典了。是否存在不建议这样做的典型情况?

【问题讨论】:

  • 感谢您的链接,克里斯。我确实指的是 Containers.Map。与 struct 的比较确实是相关的,尽管它们指的是使用 struct 字段名称作为键,而我指的是表行名称作为键。诚然,我也可以使用表字段名作为键,但它们受到更多限制。 如果我将问题的范围限制在键仅由字符串组成的情况下,那么与 Containers.Map 相比,表似乎在所有其他方面都提供了更大的灵活性。跨度>

标签: matlab dictionary matlab-table


【解决方案1】:

TL;DR: 没有。containers.Map 具有无法用 table 替换的用途。而且我不会为字典选择table


containers.Maptable 有很多不同之处值得注意。它们各有各的用途。我们可以用来创建字典的第三个容器是struct

要将table 用作字典,您只需定义一列,并指定行名:

T = table(data,'VariableNames',{'value'},'RowNames',names);

以下是这些容器在用作字典时的一些显着差异:

  • 速度:struct 的访问速度是迄今为止最快的 (10x)。 containers.Map 以等效方式(即具有行名的单列表)使用时,速度大约是 table 的两倍。

  • Keys:struct 仅限于作为有效变量名的键,其他两个可以使用任何字符串作为键。 containers.Map 键也可以是标量数字(浮点数或整数)。

  • 数据:它们都可以包含异构数据(每个值都有不同的类型),但是如果您这样做,table 会改变您的索引方式(T.value(name) 用于同类数据,T.value{name} 用于异构数据)。

  • 语法:要查找密钥,containers.Map 提供了最直接的语法:M(name)。将table 转换为字典需要毫无意义地使用列名:T.value(name)struct,如果键是由变量的内容给定的,看起来有点别扭:S.(name)

  • 构造:(参见下面的代码。)containers.Map 具有从给定数据构建字典的最直接的方法。 struct 并非用于此目的,因此它变得复杂。

  • 内存:这很难比较,因为containers.Map 是用 Java 实现的,因此whos 只报告 8 个字节(即一个指针)。 table 可以struct 更节省内存,如果数据是同质的(所有值都具有相同的类型)和标量,因为在这种情况下,一列的所有值都存储在单个数组。

  • 其他区别:

    • table 显然可以包含多个列,并且有很多有趣的方法来操作数据。

    • stuct实际上是一个struct数组,可以索引为S(i,j).(name)。当然name 可以是固定的,而不是变量,导致S(i,j).name。在这三个中,这是唯一的内置类型,这就是它高效得多的原因。

下面是一些代码,显示了这三个容器在构造字典和查找值时的区别:

% Create names
names = cell(1,100);
for ii=1:numel(names)
   names{ii} = char(randi(+'az',1,20));
end
name = names{1};

% Create data
values = rand(1,numel(names));

% Construct
M = containers.Map(names,values);

T = table(values.','VariableNames',{'value'},'RowNames',names);

S = num2cell(values);
S = [names;S];
S = struct(S{:});

% Lookup    
M(name)
T.value(name)
S.(name)

% Timing lookup
timeit(@()M(name))
timeit(@()T.value(name))
timeit(@()S.(name))

计时结果(微秒):

M: 16.672
T: 23.393
S:  2.609

【讨论】:

  • 全部正确。在某些情况下,设置文字查找表的可读性优势有利于表,如果这对上下文很重要:Literals = { 'RowName' 'NumDat'; 'dog' 9 ; 'cat' 12 ; 'mouse' pi ; 'horse' exp(1) ; }; T = cell2table( Literals(2:end,:), 'VariableNames',Literals(1,:) ); T.Properties.RowNames = T.RowName。我会将每个语句和单元格行放在单独的行中,以便立即看到表格性质和键/值关联。
  • 按照您关于操作表数据的有趣方法的观点,您可以一次查找一系列键,例如,T.NumDat({'mouse' 'dog'})。如果您有多个字符串列,您也可以将它们交换为 RowNames 以用作键。
  • @user2153235:使用Literals,您还可以轻松构建结构和Mapstruct(Literals{:})(实际上需要先转置)和containers.Map(Literals(1,:),Literals(2,:))。在这两种情况下都不需要Literals 的第一行。
  • @user2153235:如果需要这种类型的操作,那么确实可以使用table
  • 将元胞数组转换为结构体很酷。如果我需要速度优势,并且我正在对单个值进行标量查找,请记住一些事情。谢谢。
【解决方案2】:

你可以更简单,你可以使用字符串字段访问结构:

clear
% define
mydata.('vec')=[2 4 1]; 
mydata.num=12.58;
% get 
select1='num'; 
value1=mydata.(select1); %method 1 
select2='vec'; 
value2=getfield(mydata,select2) %method 2 

【讨论】:

  • 没错!您是否有在一个语句中构建查找表的代码模式,例如cell2table?我正在考虑如何简化代码。同样,促使我发布这个问题的原因是想知道字典是否提供了任何可能导致人们不完全放弃它们的东西。谢谢。
  • @user2153235 你可以使用cell2struct...不过,这些都是不同的结构,各有各的用途。
  • 我应该澄清一下,链接指向如何从单元格转换为初始化数据允许输入数据很好地布局,以便关联立即显而易见。我在对 Cris Luengo 的回答的评论中提供了一个示例,并提到了矢量化表查找的优势和方便的键交换。我一定正处于对桌子早恋的阶段。
猜你喜欢
  • 1970-01-01
  • 2018-01-04
  • 1970-01-01
  • 2016-05-28
  • 2016-08-14
  • 1970-01-01
  • 2011-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多