0

I have this array in Octave :

dwnSuccess(1,1)
ans =
{
  [1,1] =

    scalar structure containing the fields:

      site = FRED
      interval = d
      aard = logDir log/
      dwnGrootte =  log/
      time =  737861.64028

and I would like to formulate conditions to find cells containing e.g. logDir in the field 'aard'. I don't find the correct syntax. Someone knows where to find or has an example with combinations of conditions. Thanks

Tasos Papastylianou
  • 21,371
  • 2
  • 28
  • 57
patpin
  • 11
  • 1
  • 4
  • 2
    A few questions in order to clarify. 1. Do you have a cell array where each cell contains a struct? 2. Are you in charge of this code? 3. If so, have you considered just having a straightforward struct array instead? – Tasos Papastylianou Mar 11 '20 at 15:14

2 Answers2

1

Assuming that you need to keep a cell array of scalar structs (instead of a struct array which makes more sense if each struct has a defined set of fieldnames), then you need to iterate the cell array to get that field and then use logical indexing to create a new cell array with the structs of interest. Like so:

aards = cellfun (@getfield, cs, {"aard"}, "UniformOutput", false);
m = strcmp(aards, "logDir"); # this must match the whole string
filter_cs2 = cs(m); 

If you are interested on finding whether a string is somewhere in that field, then it's just a bit more complex:

m = ! cellfun ("isempty", strfind (aards, "logDir"));
carandraug
  • 12,938
  • 1
  • 26
  • 38
0

If I understood correctly your question, then suppose you have the following cell array:

a = cell();
a{1} = struct('a', 1, 'b', 'dwn', 'c', 2);
a{2} = struct('a', 2, 'b', 'notdwn', 'c', 3);
a{3} = struct('a', 3, 'b', 'dwn', 'c', 4);
a{4} = struct('a', 4, 'b', 'dwn', 'c', 5);

I think the easiest thing to do would be to first convert it to a struct array. You can do so easily via 'sequence generator' syntax, i.e.

s = [a{:}];   % collect all cell elements as a sequence, then wrap into an array

If you are in charge of this code, then I would instead just create a struct array instead of a cell array from the very beginning.

Once you have that, you can again use a 'sequence generator' syntax on the struct array, with an appropriate function that tests for equality. In your case, you could do something like this:

strcmp( {s.b}, 'dwn' )
% ans = 1  0  1  1

s.b accesses the field 'b' in each element of the struct array, returning it as a comma separated list. Wrapping this in braces causes this sequence to become a cell array. You then pass this resulting cell array of strings into strcmp, to compare each element with the string 'dwn'.

Depending on what you want to do next, you can use that logical array as an index to your struct array to isolate only the structs that contain that value etc.

Obviously this is a quick way of doing it, if you're comfortable with generating sequences in this way. If not, the general idea stands and you're welcome to iterate using traditional for loops etc.

Tasos Papastylianou
  • 21,371
  • 2
  • 28
  • 57
  • 1
    Having a cell array of scalar structs only makes sense if each scalar array have different sets of fieldnames. If that is the case, this won't work because creating the struct array (`s = [a{;}]`) will fail. – carandraug Mar 11 '20 at 16:41
  • @carandraug Good point. Though tbh, if that's the case, it would sound like OP has far worse problems :p – Tasos Papastylianou Mar 11 '20 at 18:11
  • How can one declare a structure array without creating a first element of the array? – patpin Mar 11 '20 at 21:07
  • @patpin type `help struct` for details on the syntax and how to create structs formally. Specifically, you can create an empty 3-by-4 struct array by passing an empty 3-by-4 cell as the value of each field when you create the struct array, i.e. `struct( 'foo', cell(3,4), 'bar', cell(3,4) )` – Tasos Papastylianou Mar 12 '20 at 09:39
  • I m still having problems applying multiple conditions e.g. where in the structure dwnSuccess the fields begDate = 20180101 endDate = 20200310 and dwnGrootte = and success = 1 and time = 737866.94874 , with the code dwnSuccess(2).time==737866.94874) && (dwnSuccess(2).begDate == 20180101) doesn't give a 1 – patpin Mar 16 '20 at 22:03
  • I also would like to compare without a for loop. Is that possible? – patpin Mar 16 '20 at 22:11
  • dwnSuccess(2).time==737866.94874 gives 0 and also (dwnSuccess(2).begDate == '20180101') (begDate is char) – patpin Mar 16 '20 at 22:18
  • I give a working formula here: res1=(isequal(dwnSuccess(jj).success,[1]) && (strcmp({dwnSuccess(jj).aard},aard)) && (strcmp({dwnSuccess(jj).interval},interval)) && (strcmp({dwnSuccess(jj).site},site))) – patpin Mar 17 '20 at 10:14
  • @patpin read the help documentation for strcmp. What I wrote above will work conceptually because it is intended to output a logical _array_ as an output, but what you wrote will fail because it expects a single logical scalar as an output. What I show above _is_ the way to avoid a for loop. – Tasos Papastylianou Mar 17 '20 at 11:56
  • As for why your logical test is failing, I expect this has nothing to do with the syntax itself, and more to do with the limitations of floating point arithmetic. E.g. one might logically expect `1 - 0.95 -0.05 == 0` to output 'true', but in fact this will output 'false'. You should never rely on 'equality testing' when it comes to comparing results arising from floating point calculations. See [this](https://stackoverflow.com/q/54261566/4183191) for details. – Tasos Papastylianou Mar 17 '20 at 11:59