Andy
Andy

Reputation: 8091

Use struct as index into vector

Is there a "better"(means readable and vectorized) method to use a struct with indices to generate a result struct?

# struct values are indices into b
a.foo = 2;
a.bar = 3;

b = [e pi 123 1337];

## the loopy way
for [val, key] = a
  c.(key) = b(val);
endfor

disp (c)

which gives the desired result

scalar structure containing the fields:

  foo =  3.1416
  bar =  123

or another clumsy and almost obfuscated way:

d = cell2struct(num2cell(b([struct2cell(a){:}])'), fieldnames(a));
assert (c, d);

Upvotes: 1

Views: 90

Answers (1)

Tasos Papastylianou
Tasos Papastylianou

Reputation: 22215

In theory, the lovely one-liner you're looking for is probably:

structfun (@ (x) b(x), a, 'UniformOutput', false);

However, structfun, much like its other 'fun' relatives, seems to be just syntactic sugar rather than actual vectorisation. So in fact the fastest (and arguably cleanest) method does seem to be your for loop:

Benchmark:

octave:1>  a.foo = 2; a.bar = 3; b = [e pi 123 1337];

octave:2>  # loop method #
        >  tic; for i = 1 : 100; 
        >    for [val, key] = a; S1.(key) = b(val); end; 
        >  end; toc
Elapsed time is 0.00160003 seconds.

octave:3>  # cell2struct method # 
        >  tic; for i = 1 : 100; 
        >    S2 = cell2struct(num2cell(b([struct2cell(a){:}])'), fieldnames(a));
        >  end; toc
Elapsed time is 0.006423 seconds.

octave:4>  # structfun method #
        >  tic; for i = 1: 100
        >    S3 = structfun(@ (x) b(x), a, 'UniformOutput', false);
        >  end; toc
Elapsed time is 0.279853 seconds.

PS. However, note that the for-loop approach will not work "as is" if you have an array of structs, whereas the structfun approach will.

Upvotes: 3

Related Questions