Iterating over an array in a function - krl

For my Google Docs spreadsheet module, I'd like a function to be able to accept an array of values and iterate over them, adding them to a hash. The spreadsheet submission form wants values in a format like this:
{"entry.0.single": value0,
"entry.1.single": value1,
"entry.2.single": value2}
If the function accepts an array like the following,
[value0, value1, value2]
is it possible to loop over them, keep a running counter, and create a hash? This would be a simple task in other languages. Python suffices for illustration:
hash = dict()
i = 0
for val in values:
hash["entry.%s.single" % i] = val
i += 1
Can that be done in KRL?

Recursive functions are your friend:
a = ['value0', 'value1', 'value2'];
r = function(a, h, n){
top = a.head();
newhash = h.put({'entry.#{n}.single':top});
a.length() > 1 => r(a.tail(), newhash, n+1) | newhash;
};
out = r(a, {}, 0);
out has the value of {'entry.1.single' :'value1','entry.0.single' :'value0','entry.2.single' :'value2'};
A recursive function is needed here because you are doing a structure conversion. If you wanted an array back, you could have used the map() method.
Also, watch your base case writing recursive functions. KNS does enforce a recursion limit.

Related

Maximum value of fields of nested structure

I have following structure:
S.s1.val = 1;
S.s2.val= 5;
S.s3.val= 4;
...
S.s10.value = 3;
How can I find max value of all val fields without using loops. And what is general solution to apply functions to all nested structure fields?
There is no general solution, but one way to think of is structfun to collect the data you want to process to an array.
maxval = max( structfun(#(x) x.val, S) )
Internally structfun works serially like a loop, so if you're really into speed, don't use structs (or cell arrays).

Concatenating (sub)fields of structs in a cell array

I have a Matlab object, that is a cell array containting structs that have almost identical structures and I want to programmatically get a (sub)field of the structs of all cell array elements.
For example, we take test
test = {struct('a',struct('sub',1)), struct('a',struct('sub',2),'b',1)};
This will create a cell array with the following structure:
cell-element 1: a --> sub --> 1
cell-element 2: a --> sub --> 2
\-> b --> 1
It can be seen that the elements of test don't have the exact same structure, but similar. How can I get all values of the a.sub fields of the elements of the cell. I can obtain them in this specific problem with
acc=zeros(1,numel(test));
for ii=1:numel(test)
acc(ii) = test{ii}.a.sub;
end
but I can't quite get this method to work in a more general context (ie. having different fields).
You may want to use the function getfield:
%//Data to play with
test = {struct('a',struct('sub',1)), struct('a',struct('sub',2),'b',1)};
%//I'm interested in these nested fields
nested_fields = {'a', 'sub'};
%//Scan the cell array to retrieve the data array
acca = cellfun(#(x) getfield(x, nested_fields{:}), test);
In case your data cannot guarantee that all the elements are the same type and size, then you need to output a cell array instead:
%//Scan the cell array to retrieve the data cell array
accc = cellfun(#(x) getfield(x, nested_fields{:}), test, 'UniformOutput', false);
Later Edit
If one wants to use different sets of nested fields for each cell element then:
%//nested_fields list should have the same size as test
nested_fields = {{'a','sub'}, {'b'}};
accm = cellfun(#(x,y) getfield(x,y{:}), test, nested_fields, 'UniformOutput', false);
Edit: No need for recursion, as shown by #CST-link:s answer; the native getfield function can neatly unfold a cell array of fields as its second argument, e.g. getfield(foo{i}, fields{:}) instead of the call to the recursive function in my old answer below. I'll leave the recursive solution below, however, as it could have some value in the context of the question.
You can build you own recursive version of getField, taking a cell array of fields.
function value = getFieldRec(S,fields)
if numel(fields) == 1
value = getfield(S, fields{1});
else
S = getfield(S,fields{1})
fields{1} = [];
fields = fields(~cellfun('isempty',fields));
value = getFieldRec(S,fields);
end
end
Example usage:
foo = {struct('a',struct('sub',1)), ...
struct('a',struct('sub',2),'b',3), ...
struct('c',struct('bar',7),'u',5)};
accessFields = {'a.sub', 'b', 'c.bar'};
values = zeros(1,numel(foo));
for i = 1:numel(foo)
fields = strsplit(accessFields{i},'.');
values(i) = getFieldRec(foo{i},fields);
end
With the following result
values =
1 3 7
I have found a way to do this using eval:
function out = catCellStructSubField(cellStruct, fieldName)
out = zeros(1,numel(cellStruct));
for ii = 1:numel(cellStruct)
out(ii) = eval(['cellStruct{ii}.' fieldName]);
end
Where it can be used on my test example like this:
catCellStructSubField(test, 'a.sub')
Dynamic field names (cellStruct{ii}.(fieldName)) does not work because I'm accessing sub-fields.
I know eval is often a bad idea. I'm curious for different solutions.

Coffeescript iteration over array of objects does not compile as expected

I would like to perform an iteration over an array of objects. Instead of writing
for item in items
for k, v in item
# Do Something
I would like to do something similar to this
for k,v of item in items
# Do something
Which based on the compiled output is not supported:
var k, ref, ref1, v, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
ref1 = (ref = indexOf.call(items, item) >= 0) != null ? ref : [];
for (k in ref1) {
v = ref1[k];
# Do something
}
Is there any other comprehension-like operation through which I can perform this shortcut?
EDIT: I can refer to specific keys in the object by doing
for { k1, k2 }, i in items
# Do something
For the sake of the question, assume the keys are dynamic
No you can't. Following coffeescript's golden rule “it's just JavaScript”, consider looking at the source where a for loop gets translated. You will need two Javascript fors and you only can get one from a coffescript for (the for gets inserted in line 2079).
The javascript result you want to have is something like this:
for(_i…;…;…){
var _x = items[_i];
for(k in _x){
var v = _x[k]
…
}}
There are only two ways to get a javascript for loop (apart from the prewritten ones, like in class definitions): On “Range compilation”, which always gives a for(…;…;…) loop (which contructs an array inside a closure that will be returned) and for the for construct.
Your example to access single keys works because you are using some very special case of destructuring assignment. What you would need is a destructuring that extracts key-value pairs and there is none. If you look at the compiled example constructs like this get translated into a=items[i].a so such that there is no iteration. You even can omit the ,i:
for {a} in items
#iterate over the .a values of items
If your #Do something is just one line, you can put your fors on one line, but I personally think it doesn't increase the readability.
console.log [k,v] for k,v of i for i in items

loop starting from given index

Considering the following javascript, what's the best way to write this loop in coffee script, given the initial index is greater than 0:
function mixin(target, source, methods) {
for (var i = 2, l = arguments.length; i < l; i++){
var method = arguments[i];
target[method] = source[method].bind(source)
}
}
Automatic code converters suggest use a while loop like this:
mixin = (target, source, methods) ->
i = 2
l = arguments.length
while i < l
method = arguments[i]
target[method] = source[method].bind(source)
i++
Is there a cleaner way to do this?
You'd usually use a splat in CoffeeScript when defining your mixing function:
The JavaScript arguments object is a useful way to work with functions that accept variable numbers of arguments. CoffeeScript provides splats ..., both for function definition as well as invocation, making variable numbers of arguments a little bit more palatable.
So you'd say:
mixin = (target, source, methods...) ->
# splat ----------------------^^^
for method in methods
target[method] = source[method].bind(source)
and your problem goes away. The splat in the argument list will collect all the arguments after source into a methods array for you so you won't have to worry about arguments at all; the splat also makes the function's signature nice and obvious.
Use an exclusive range (triple dot, excludes the number at the highest.
for i in [2...arguments.length]
method = arguments[i]
target[method] = source[method].bind(source)
If you have 5 things in your args, this will hit indexes 2, 3 and 4.

Better code for accessing fields in a matlab structure array?

I have a matlab structure array Modles1 of size (1x180) that has fields a, b, c, ..., z.
I want to understand how many distinct values there are in each of the fields. i.e.
max(grp2idx([foo(:).a]))
The above works if the field a is a double. {foo(:).a} needs to be used in the case where the field a is a string/char.
Here's my current code for doing this. I hate having to use the eval, and what is essentially a switch statement. Is there a better way?
names = fieldnames(Models1);
for ix = 1 : numel(names)
className = eval(['class(Models1(1).',names{ix},')']);
if strcmp('double', className) || strcmp('logical',className)
eval([' values = [Models1(:).',names{ix},'];']);
elseif strcmp('char', className)
eval([' values = {Models1(:).',names{ix},'};']);
else
disp(['Unrecognized class: ', className]);
end
% this line requires the statistics toolbox.
[g, gn, gl] = grp2idx(values);
fprintf('%30s : %4d\n',names{ix},max(g));
end
Indeed, there is a better way. Surprisingly, MATLAB allows you to access the struct fields using a key string without eval, for instance:
Models1(1).(names{ix})
so instead, you can write this:
className = class(Models1(1).(names{ix});
...
values = [Models1(:).(names{ix})];
...
values = {Models1(:).(names{ix})};
Also, instead of using class and strcmp, you can just test the same conditions with isa:
v1 = Models1(1).(names{ix});
if (isa(v1, 'double') || isa(v1, 'logical'))
values = [Models1(:).(names{ix})];
% # ...
elseif (isa(v1, 'char'))
values = {Models1(:).(names{ix})};
% # ...
else
disp(['Unrecognized class: ', class(v1)]);
end
It should be much faster.