Ember.Array: how can I make several changes atomically? - arrays

I have an Ember.Array that I need to rearrange by moving one element to another. Right now, I have the function:
moveElement: (from, to) ->
from_value = array.objectAt(from)
array.removeAt(from)
array.insertAt(to, from_value)
The problem is, I use this array in a computed property and that is firing in between the removeAt and insertAt. How can I make sure these changes are atomic?
Thanks!

So, I managed to get it working by using arrayContentWillChange, arrayContentDidChange, and array primitives:
moveElement: (from, to) ->
array = #get('array')
# make all changes to array atomically
array.arrayContentWillChange(from, 1, 0)
from_value = array[from]
array.splice(from,1)
array.splice(to,0,from_value)
array.arrayContentDidChange(to, 0, 1)
I'm not sure if I'm using the arrayContent..Change functions correctly. They take 3 arguments: startIdx, removeAmt, addAmt. Which represent the start index, number of elements to remove, and number of elements to add. I used my from and to values to show that I am removing one element at from and adding one element at to.
Seems to be working now.

Related

Most efficient algorithm to convert array A into array B of unknown lengths

I have an array of indefinite length from which the user chooses to add/remove components. To reflect the changes in the backend I must perform ajax requests.
My question is what would be the most efficient way to reflect those changes?
Currently I have two approaches in mind:
1.) Find the differences between the two arrays and then appropriately address the differences by adding the missing / removing the extra elements one by one.
2.) Make use of the remove all service to remove every single item in the array in the backend using a single request then adding one by one whatever is in the second array.
At the first glance approach 1 seems to be better with small changes in particular. However if the user decides to remove 80 or so elements from the array and only add 2 more then approach 2 outclasses approach 1.
Perhaps there is a better solution?
Thanks!

C: deleting elements mid array and have previous pointers working

I have several arrays like this (please ignore specific names):
static resource_t coap_cmp_res[MAX_CMPS];
e.g. [cmp1,cmp2,cmp3,cmp4,cmp5,0,0,0]
and a code that uses these elements, for example, coap_cmp_res[4] (cmp5) is associated with a REST resource, call it Res5.
At a certain point in time, I delete an element in that array at position x like this:
rest_deactivate_resource(&coap_cmp_res[x]);
e.g. for x = 2
[cmp1,cmp2,0,cmp4,cmp5,0,0,0]
What I then would like to do is have a single continuous array again like this
e.g. [cmp1,cmp2,cmp4,cmp5,0,0,0,0]
What I do currently is:
for(UInt8 i = x; i < MAX_CMPS; i++){
coap_cmp_res[i] = coap_cmp_res[i+1];
}
which gives [cmp1,cmp2,cmp4,cmp5,cmp5,0,0,0]
then I manually set the last non-zero element to 0.
e.g. [cmp1,cmp2,cmp4,cmp5,0,0,0,0]
So, this looks good, but the problem is that the Res5 is still associated with coap_cmp_res[4] and thus now the value 0, instead of cmp5, which is not what I desire.
I could deactivate and reactivate every resource after x in the array to have the associations working again, but was wondering if there was a more efficient way to go about this.
Hopefully this makes sense.
As the proverb says: "add a level of indirection". An array of resource_t* that point into coap_cmp_res and are stable. Then have Rea5 associated with a pointer, and use the indirection to reach into a valid entry.
static resource_t coap_cmp_res_data[MAX_CMPS];
static resource_t* coap_cmp_res_ptrs[MAX_CMPS]; // points into coap_cmp_res_data
When you remove an element, you update the entries in coap_cmp_res_ptrs, without moving them, and shrink coap_cmp_res_data. Any resource will still refer to the same position in coap_cmp_res_ptrs, and the indirection will take it to the current location of the resource.
An alternative approach, which may prove better in your case (you'd have to profile), is to use node based storage. I.e a linked list.

How to add and remove objects from an array in Eiffel

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?

Remove a term from an array during a for loop

I've been creating a system for storing objects that persist for a specified duration, then remove themselves. However, I'm having some trouble figuring out how to remove expired items from the array while the for loop is running (to minimize extra iterations through the array)
Here is what I've made so far. Terms in the list are flagged with a Boolean value indicating that they're done.
For i = 0 To VisualEffects.Count - 1 Step 1
VisualEffects(i).Update(gt)
VisualEffects(i).Draw(sb, Pos, Cam)
If VisualEffects(i).CD.isExpired() Then
VisualEffects.RemoveAt(i)
i = -1
End If
Next
Why does this produce an error? How can I remove a term from an array and continue iterating through the remainder of the loop?
Regards
Ares
The line
i = -1
sets i to -1, causing the For loop to terminate.
If you can, reverse the order of the loop so that you start with the last array element and count down. That makes the remove logic much more straightforward.
.NET arrays are fixed-size so you can't actually remove an element from an array at all. You can change the value of an element, so you can set an element to Nothing to remove the object that it referred to, but the element is still there. If you read the MSDN documentation for the Array class, you'll see that the RemoveAt method throws a NotSupportedException for this reason.
If you're actually using a collection rather than an array then you can call RemoveAt but you need to loop from the last index to the first rather than first to last. That way, removing an item will not affect the indexes of those items that you are yet to visit.

ActionScript Custom Sort Function

I'm attempting to write a sort function to use with Array.sort(). I'm a bit stuck on how I can write exactly what I need though.
In my app items are added to this array at different times throughout execution, and each time an item is added, the array is sorted. The items in the Array are all objects and all have a property "weight". If a weight is greater, the item should go first, if it's less the item should go after. That is easy and I have a function that looks like this:
return a.weight - b.weight;
The problem is I have an added requirement that if an item is added later and it has the same weight as another item it MUST be put after that item in the array. It MUST go behind every item in the array that has already been added which has the same weight.
I'm having trouble coming up with a function to make sure that requirement is met every time.
Thanks for the help!
No need for writing a custom sort, the Array's sortOn can handle this case.
You will however need to add a new member to your items, I'll call it 'timestamp'.
arr.sortOn( [ 'weight', 'timestamp' ], [ Array.NUMERIC | Array.DESCENDING, Array.NUMERIC ] );
The first parameter defines which properties will be used for sorting, the second defines the options for each field. See http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Array.html#sortOn() for more info.
The |-operator (bitwise OR-operator) is used to pass multiple options for one field.
So, in this case, the first field ('weight') gets sorted numerically and descending.
--EDIT:
For Vectors you need to use a comparison function:
var sortFunc : Function = function (x: <T>, y : <T>):Number{
var dw:Number = y.weight - x.weight
if( dw ==0 ){
//returns negative if y was added later
return x.timestamp - y.timestamp;
}else{
//returns negative if x has a higher weight
return dw;
}
}
vec.sort( sortFunc );
I would suggest to add another property to the object. Something like :
a.index = i; // where, i is the index before sorting
This will allow you to keep track of the order it entered the list before sorting.
Besides this you may also consider keeping another copy of the array itself (with index intact).

Resources