Trying to do something like
a: ARRAY[STRING]
create a.make_empty
a.put("foo foo fool")
a.wipe_out
Do I have to? or is there another way as STRING doesn't seem to have a .has_default
create a.make_empty
a.put("foo foo fool")
create a.make_empty
The most straightforward way is to use keep_head (n). It keeps only first n items, therefore, when n = 0, all items are removed altogether:
a.keep_head (0)
Another way is to use a creation procedure, for example, make_empty as a regular one. It is going to set an array to the state of a newly created one:
a.make_empty
However, this approach looks a bit odd. And it can change lower index of the array. So, keep_head is preferable.
Note. ARRAYED_LIST is a good alternative to ARRAY: it has almost all features of ARRAY, is more flexible, has other features, and wipe_out among them.
Related
Possibly very stupid question I cannot seem to find an answer for (I am beginning with code)
I want to create a simple loop which appends myArray with three objects, which are members of a custom class MyClass. The objects have the following names: "object1", "object2", "object3".
When I write the following code, there is no issue:
myArray.append(object1)
But I want to write a loop to add all three. Again, very dumb, but I can't figure out how to insert the number in the name of the object as a variable. E.g., here was something I tried
let x = 3
for i in 1...x {
myArray.append(object[i])
}
This gives an error. The reason I want to do it using a loop, and not simply write in the three objects manually, is that I won't always loop three times. Sometimes I'll just want the first two objects, sometimes just the first.
I assume there's some easy way to do this, but when I search it tends to turn up more complex questions
I am trying to make a CONTAINER class that maintains an array of CRITTER objects (that I have already created and tested. Note, there are various CRITTER subspecies, that are inheriting from the CRITTER super class). The aim is to add and remove CRITTER objects from this array. This is what the CONTAINER class looks like:
class
CONTAINER
create
make
feature
num: detachable INTEGER
list: ARRAY[CRITTER]
make
local
do
create list.make_empty
num := 0
end
addCritter(critter: CRITTER)
do
list.put(animal, num)
num := num + 1
end
removeCritter(critter: CRITTER)
do
list.put (list.at (num), ???) -- put last element in position of element to be removed
list.remove_tail (num) -- remove tail
num := num - 1
end
end
Two issues:
Firstly, I can instantiate the CONTAINER class inside APPLICATION, but when I call
create container.make
container.addCritter(myCritter)
I get a precondition, invalid index violation error on the second line. This may be because I have not set the upper and lower bounds of the array. However, when I try to do so, I get syntax errors. Which is the way to solve this issue?
Secondly, in order to remove an object from the array, it would help if I could get hold of the index value, but I can't see any function that does this, unless I am missing something.
ARRAYs are usually used for fixed-length containers. In your case, with lots of dynamic changes, it's better to use more dynamic structures, for example, ARRAYED_LIST. Similar to ARRAY it provides features to access items by their index, but there are also more convenient ones. New elements can be added by using feature extend. Old elements can be removed by using feature prune if only one element matching a given one needs to be removed, or prune_all, if all matching elements need to be removed. The word "matching" denotes either reference or object equality, depending on which comparison criteria is required: = or ~. The comparison criteria is changed using feature compare_objects.
Some general observations:
There is no need to track number of elements yourself, usually there is a feature count that provides this number.
Indexes in Eiffel usually start with 1, not 0.
The declaration detachable INTEGER is equivalent to INTEGER because INTEGER is expanded and all expanded types are attached regardless of any attachment marks.
The following discussion might also be useful:
How to initialise an array of objects in Eiffel?
this is the problematic:
I got a master array, it's an array that have all the entities in the game.
When an entity (unit, building, etc) dies, I remove that entity from the array.
Now, I got other several arrays that are "subgroups" from that array. Like, enemyEntities, alliedEntities, movingEntities, etc. Everytime I create a new entity I add it to the corresponding array.
Everything works ok, but, when I remove one element from the master array, I'd like to somehow automatically remove it from the other arrays, let say, in an elegant way.
Any ideas?
Have a remove-method which takes care of it all. Make it first remove it from the master array, and then from each sub arrays (if the object is found). A nicer way of doing it might be to put all arrays in a another array, and do that to each of them in a loop.
Is there an elegant way to express
val a = Array.fill(2,10) {1}
def do_to_elt(i:Int,j:Int) {
if (a.isDefinedAt(i) && a(i).isDefinedAt(j)) f(a(i)(j))
}
in scala?
I recommend that you not use arrays of arrays for 2D arrays, for three main reasons. First, it allows inconsistency: not all columns (or rows, take your pick) need to be the same size. Second, it is inefficient--you have to follow two pointers instead of one. Third, very few library functions exist that work transparently and usefully on arrays of arrays as 2D arrays.
Given these things, you should either use a library that supports 2D arrays, like scalala, or you should write your own. If you do the latter, among other things, this problem magically goes away.
So in terms of elegance: no, there isn't a way. But beyond that, the path you're starting on contains lots of inelegance; you would probably do best to step off of it quickly.
You just need to check the array at index i with isDefinedAt if it exists:
def do_to_elt(i:Int, j:Int): Unit =
if (a.isDefinedAt(i) && a(i).isDefinedAt(j)) f(a(i)(j))
EDIT: Missed that part about the elegant solution as I focused on the error in the code before your edit.
Concerning elegance: no, per se there is no way to express it in a more elegant way. Some might tell you to use the pimp-my-library-Pattern to make it look more elegant but in fact it does not in this case.
If your only use case is to execute a function with an element of a multidimensional array when the indices are valid then this code does that and you should use it. You could generalize the method by changing the signature of to take the function to apply to the element and maybe a value if the indices are invalid like this:
def do_to_elt[A](i: Int, j: Int)(f: Int => A, g: => A = ()) =
if (a.isDefinedAt(i) && a(i).isDefinedAt(j)) f(a(i)(j)) else g
but I would not change anything beyond this. This also does not look more elegant but widens your use case.
(Also: If you are working with arrays you mostly do that for performance reasons and in that case it might even be better to not use isDefinedAt but perform validity checks based on the length of the arrays.)
I am playing around with OOP in MATLAB, and I have the following constructor:
function obj = Squadron(num_fighters, num_targets, time_steps)
if nargin == 0
num_targets = 100;
time_steps = 100;
num_fighters = 10;
end
obj.num_shooters = num_fighters;
for iShooter = 1:obj.num_shooters
a(iShooter) = Shooter(num_targets, time_steps);
end
obj.ShooterArray = a;
obj.current_detections = zeros(num_fighters, num_targets);
end
That temporary variable 'a' smells terrible. Is there a better way to initialize an array of objects, I wish there was a push/pop method. I am sure there is a better way to do this.
Looks like you are trying to create an array of handle objects (Shooters) and store it inside the property of another handle object (a Squardron). I have had a very similar problem discussion that might help you.
In short: What you are doing might not be pretty - but might be pretty good already.
When creating an array in Matlab it is usually a good Idea to do some pre-allocation to reserve memory which speeds up performance significantly.
In a normal case something like this:
a=zeros(1,1000);
for n=1:1000
a(n)=n;
end
(here a=1:1000; would be even better)
For objects the pre-allocation works by assigning one of the objects to the very last field in the array. Matlab then fills the other fields before that with objects (handles) that it creates by calling the constructor of that object with no arguments (see Matlab help). Hence a pre-allocation for objects could look like this:
a(1,1000)=ObjectConstructor();
for n=1:1000
a(n)=ObjectConstructor();
end
or simply
for n=1000:-1:1
a(n)=ObjectConstructor();
end
Making sure Shooter can be called with no arguments you should be able to do something like:
for iShooter = obj.num_shooters:-1:1
obj.ShooterArray(iShooter) = Shooter(num_targets, time_steps);
end
However, it turns out that for some reason this direct storing of an array of objects in another object's property creates very bad performance. (Probably the array pre-allocation does not work well in this case). Hence using an auxiliary variable and allocating the full array at once to the property is in this case is a good idea to increase performance.
I would try:
for iShooter = obj.num_shooters:-1:1
a(iShooter) = Shooter(num_targets, time_steps);
end
obj.ShooterArray = a;
Again - for more detail see this discussion
There are a couple of ways to handle this situation...
Building object arrays in the constructor:
You could modify your Shooter class such that when you pass arrays of values it creates an array of objects. Then you could initialize ShooterArray like so:
obj.ShooterArray = Shooter(repmat(num_targets,1,num_fighters),...
repmat(time_steps,1,num_fighters));
Replicating instances of a value class:
If Shooter is a value class, and each object is going to be exactly the same (i.e. you don't initialize any of its default properties to random values), then you can create just one object and replicate it using REPMAT:
obj.ShooterArray = repmat(Shooter(num_targets,time_steps),1,num_fighters);
Unfortunately, if Shooter is a subclass of the handle class, you can't just replicate it as you can with a value class. You would actually be replicating references to just one object, when you really need a number of separate objects each with their own unique reference. In such a case, your current code is likely the best solution.