dynamic array of objects in Matlab - arrays

I have created this two codes classes.
classdef master < matlab.mixin.Copyable
properties
id
list
end
methods
function this=master(id)
if nargin > 0
this.id = id;
this.list = repmat(msg,1,20);
end
end
end
end
classdef msg < matlab.mixin.Copyable
properties
id
dest
ttl
end
methods
function this=msg(id,dest,ttl)
if nargin > 0
this.id = id;
this.dest = dest;
this.ttl = ttl;
end
end
end
end
In another part of my code I try to delete one or more objetc "msg" from array "master.list" using the following:
function verifyMsgToDiscard(this,t)
i = 1;
while (i <= numel(this.list))
m = this.list(i);
if (t > m.ttl)
this.list = this.list(this.list~=m); %remove m of the list
clear m; %delete m from the system
end
i= i + 1;
end
end
I am getting the error:
Index exceeds matrix dimensions.
Error in master/verifyMsgToDiscard (line 117)
m = this.list(i);
The problem I think is why I am iterating over the master.list in the same time I modify the number of elements on it. In addition I can add and remove new objects "msg" in the "list" then its size varies. How I can do this in a dynamic way.

I suppose you're trying to remove msg objects having ttl to be smaller than t. This is the Matlab way of removing elements:
this.list = this.list(t <= [this.list.ttl]);
Note that t <= [this.list.ttl] generates a logical index.

Related

Remove the OVERLAP of two arrays in snowflake

I have two arrays:
brands_followed = {'gucci', 'prada'}
brands_unfollowed = {'prada'}
I'm looking to keep only the elements in brands_followed that don't occur in brands_unfollowed - i.e. remove the intersection:
final_brand_selection = {'gucci'}
I see array_intersection() will tell me the elements in both. (But actually brands_unfollowed is a subset of brands followed so it's not useful.) How do I remove the unfollowed brands?
You could use a Javascript UDF for this:
CREATE OR REPLACE FUNCTION array_final(a array, b array)
RETURNS array
LANGUAGE JAVASCRIPT
AS
$$
var c = [];
for (var i = 0; i < A.length; i++){
if (B.includes(A[i]))
continue
else
c.push(A[i])
}
return c
$$;
Then a select:
select array_final(PARSE_JSON('["gucci","prada"]'), PARSE_JSON('["prada"]'));
would give me something like this:

getDisplayValues is not returning a 2-D array

I am writing a script that updates a cell in a Google Sheet based on the intersection of a Row and Column. I find the row by iterating through a list of unique teacher names. When I find the name, I capture its row number in the variable "row". I then iterate through a range of column headers that are dates to find the specific date, and capture its column number as the variable "column". However, when I look at the structure of each object in my code, the "names" object appears as [[Person1], [Person2],..., [PersonX]] whereas the "dates" object appears as [[date1, date2,..., dateX]]. I can iterate through the names object just fine, but the dates object, not so much, and I suspect it is due to the structure.
I understand that the getDisplayValues returns a string and it works fine in another area of my code when I need to grab the date from a cell and name it "dateValue". But when I look for that dateValue in the "dates" object in the code below, that is where my code fails.
Here is a sample of the code:
function updateTracker(){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var teacherName = sheet.getRange('F7').getDisplayValue();
var dateValue = sheet.getRange('N7').getDisplayValue();
var tracker = SpreadsheetApp.openById('AAAbbbCCCxxxYYYzzz111222333');
var tab = tracker.getSheetByName('Tracker');
var names = tab.getRange(1, 4, tab.getLastRow(), 1).getDisplayValues();
var dates = tab.getRange(1, 1, 1, tab.getLastColumn()).getDisplayValues();
for (var i in names) {
if (names[i][0] === teacherName) {
var row = parseInt(i+1);
}
}
for (var j in dates){
if (dates[0][j] === dateValue) {
var column = parseInt(j+1);
}
}
var cell = tab.getRange(row, column).setValue('x');
}
I get an error on that last line that getRange expects (number, number) but it getting (number, null).
Any suggestions on editing the code?
Logic:
In case of [[Person1], [Person2],..., [PersonX]], You iterate the "outer" array. There are X elements in the outer array. Each element itself is a array("inner") like [Person1] with only 1 primitive element each lime Person1.
Whereas the "dates" object appears as [[date1, date2,..., dateX]]. There is only 1 element in the outer array[date1, date2,..., dateX] and this array contains many elements like date1.
Solution:
You should iterate the inner array in the dates array:
for (var j in dates[0]){//note `[0]`
Using for...in to iterate arrays is also considered bad practice. Use for...of instead:
let column = null, j = 0;
for (const date of dates[0]){
j++;
if (date === dateValue) {
column = parseInt(j+1);//also bad to declare var in a block. Moved declaration outside
}
}
References:
What does the range method getValues() return and setValues() accept?
Why is using "for...in" for array iteration a bad idea?
for...of -MDN reference

Return array of objects from function - VBA

I need to "return" an Array of Objects from a function that I created using VBA. When I try to set the function as the array it gives me an error message, saying
Object is required.
I am not very used to VBA, and I can't fix this. Here is the function code:
Function sortedList(listRange As Integer, tempList() As ship) As ship
Dim temp As ship
Set temp = Nothing
For i = listRange - 10 To 1 Step -1
For j = 2 To listRange - 10
If tempList(j - 1).Arrival > tempList(j).Arrival Then
Set temp = tempList(j - 1)
Set tempList(j - 1) = tempList(j)
Set tempList(j) = temp
End If
Next j
Next i
'return tempList - how?
Set sortedList = tempList
End Function
Ship is a "class" that I created. tempList is the array of objects from class ship that I need to return from the function sortedList.
The function works, it's just the return part that I can't make work.
Thanks for the help. If more information is necessary let me know!
Declare the function to return an array
Function sortedList(listRange As Integer, tempList() As ship) As ship()
and then assign the result without Set
sortedList = tempList

MATLAB: add field to structure within a for loop

I have a nested for loop and would like to create named fields within the first loop and then save to that field within the next loop. Something like the below code where the first iteration would create structure.first and add 'works' to that field. Thanks!
structure = [];
namelist = ['first', 'second', 'third'];
p = 5;
for i = 1:p
structure(end+1) = struct(namelist(i), {});
for j = 1:10
if condition = true
structure(j).namelist(i) = 'works';
end
end
end
A few problems with your code. Here's a cleaned up version. Note that the best way to add a field to a structure from a string value is of the form: <<struct_name>>.(<<field_name_str>>) = <<value>>. Also, the if statement tests whether a condition holds or not, so no need to test if it is true. Finally, namelist should be stored as a cell array.
structure = [];
namelist = {'first', 'second', 'third'};
for i = 1:length(namelist)
for j = 1:10
if condition
structure.(namelist{i})='works';
end
end
end

MATLAB: Array of structure initialization in CLASS properties

I would like to create a file which will store properties containing desired values.
Each property has to be defined as an array of struct.
My current way of array of struct initialization:
classdef myClass < handle
properties(Constant)
myProp1 = struct(...
'Name', {'A','B'},...
'Value', {'1','2'});
end
end
How I wish to write my array of struct(which I feel is more clean and readable):
classdef myClass < handle
properties(Constant)
myProp1(1).Name = 'A';
myProp1(1).Value = 1;
myProp1(2).Name = 'B';
myProp1(2).Value = 2;
end
end
How should I go about achieving this?
Thanks
I think it's not possible to create structures in the properties definition like you proposed. (See my comment on your question). An alternative is to create the array of structs in the constructor. Use (SetAccess=private), so that the properties may not be changed from outside.
% myClass.m
classdef myClass < handle
properties(SetAccess=private)
myProp1 = struct
end
methods
function obj = myClass() % constructor
obj.myProp1(1).Name = 'A';
obj.myProp1(1).Value = 1;
obj.myProp1(2).Name = 'B';
obj.myProp1(2).Value = 2;
end
end
end
You can solve this issue by using object composition.
It seems that the property myProp in myClass represents something else. For sake of simplicity I will assume it is a person (you will need to adapt the example to cover your needs). You can create a Person class with properties Name, Value, ParentName and use it in your class. The property section in myClass would look like this:
myProp(1) = Person(name1, value1, parent_name1);
myProp(2) = Person(name2, value2, parent_name2);
...
myProp(N) = Person(nameN, valueN, parent_nameN);
Alternatively you can prepare your Person class to accept arrays as inputs:
names = {name1, name2, ..., nameN};
values = [value1, value2, ..., valueN];
parent_names = {pname1, pname2, ..., pnameN};
... %//possibly more code here
myProp = Person(names, values, parent_names);
and the class Person would take care of always keep them in the right order, provide setters and getters, etc.
A stub of a Person class for the first solution would look like this (a class accepting arrays would be longer):
classdef Person < handle
properties (Access = private)
name = '';
value = 0;
parent_name = '';
end
methods (Access = public)
function this = Person(name, value, parent_name)
this.SetName(name);
this.SetValue(value);
this.SetParentName(parent_name);
end
function SetName(this, name)
this.name = name;
end
function SetValue(this, value)
this.value = value;
end
function SetParentName(this, parent_name)
this.parent_name = parent_name;
end
end
end
There's nothing wrong with your original way of setting up myProp.
But if you're concerned just about readability, you could add a private static method called something like makeMyProp, which can be laid out as attractively as you want, which returns a filled out structure myProp.
Then, in the properties section, say myProp = myClass.makeMyProp;.
classdef myClass < handle
properties(Constant)
myProp1a = struct('Name','A','Value',1);
myProp1b = struct('Name','B','Value',2);
myProp1 = [myClass.myProp1a, myClass.myProp1b];
end
end
You could use enumeration(yes, this apparently exists in MATLAB).
An example usage would be:
classdef ExampleEnum < uint8 %// Can also be another datatype
enumeration
%// name value
A (1)
B (2)
end
end
Then MATLAB automatically uses the string or the value depending on how you use your enum object (this is mentioned in the documentation).

Resources