Issue when splicing array of objects - javascript

I have a vue application that gets a set of objects from an external REST API.
In a component, I sort and filter the object into an array of objects based on a field called rank, like this:
let myResults = _.orderBy(this.search_result, 'rank', 'desc').filter(service => (service.rank >= 5) ? service: "");
I then need to move a single element/object to the end of the list before rendering it, however, when I tried to do this:
let index = myResults.findIndex(e => e.name === 'Target Element');
myResults.push(myResults.splice(index,1));
It didn't work; It pushed an empty element back to the list. Eventually, I got it working by doing the following:
myResults.push(myResults.splice(index,1)[0]);
I noticed the splice was creating an array that looked like [object, object] with all the target object in the zero index object.
I don't really understand why this happened. Have I done something to the original object somewhere or is this a vue thing?

JavaScript Array.prototype.splice() returns an Array.
Return value
An array containing the deleted elements.
If only one element is removed, an array of one element is returned.
If no elements are removed, an empty array is returned.
Since an Array is returned, you're .push()-ing and Array into an existent array. As you noticed correctly, you need to extract that one Object using removedItems[0], making
myResults.push(myResults.splice(index,1)[0]);
or equally
// Remove from array 1 item
const removedItems = myResults.splice(index, 1); // Array of removed items
// Get the first Object from array
const item = removedItems[0]; // Object
// Append one Object
myResults.push(item);
the correct approach.

Related

Why can my js code set values to undefined array indexes?

As I know an Array element in JavaScript can itself be another Array, hence creating layers of arrays within one another. I am tring to define an array like:
[Array(821), Array(821), Array(821), Array(821)]
As You see, this is an array with 4 elements each of which will contain an array of 821 elements.
Now, I also know Arrays can be dynamically resized using Array.push("new value") method, otherwise an undefined error will be thrown. Therefore, I defined each and every one of the array elements as being an array itself:
var htmlOBJs = {};
htmlOBJs.tabular = [];
for (var i = 0; i < 5; i++){
htmlOBJs.tabular.push([]);
}
Now, when I want to access an element inside the inner array htmlOBJs.tabular[2][100], surprisingly no undefined error is thrown. Why? Am I not supposed to push indexes up the inner array up to 100?
The reason the undefined error isnt thrown is as you push to the tubular array this causes a new entry created. This means now it is a multidimensional array. To cause the undefined error to throw you would have to go 3 levels deep.
There is an interesting reason for empty arrays which has been described way better but basically the first parameter for the Array constructor is a size and not actually filling this array:
to do this you can use the fill method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill - you may need to map over this after to make sure these are unique values.

Iterate over array of object using map till the second last object

I am having an array of objects where all objects have the same keys except the last object. Think like array have values and to denote all these values as a whole I have a key I am pushing the key at last along with the values in the array.
homeTask is a list of object which is the values and homeTaskKey is the key to represent the homeTask
res.data.resultSet.homeTask.forEach(element => {
var singleEvent={
task:'',
taskDuration:'',
status:'',
};
singleEvent.task=element.task;
singleEvent.taskDuration=element.taskDuration;
singleEvent.status=element.status;
newEvents.push(singleEvent);
});
newEvents.push(res.data.resultSet.homeTaskKey);
addEvent(newEvents);
}
addEvent is props method of parent component where I am setting the array to state variable name as events which is array type.
When I iterate over events using map I want to skip the last object since it does not have keys like task, taskDuration and status. Therefore it won't give any problem when I fetch those values.
events.slice(0, events.length-1).map(<function>);
this will ignore the last element and all n-1 entries will be fed to map
UPDATE:
the array name is events not event therefore it should be events.length
You could still use map, but simply pop the last element off once the map completes. For example:
const newEvents = homeTask.map(({ task, taskDuration, status }) => ({
task, taskDuration, status
}))
newEvents.pop()
addEvent(newEvents)
Or just replace the last item with your taskkey, as you know the last item will be junk:
newEvents[newEvents.length - 1] = res.data.resultSet.homeTaskKey
Or just slice the array prior to mapping, and then push the taskKey at the end like you were doing. slice is safe to perform on your prop, as it shallow copies.
Or most importantly, ask yourself why you have this entirely weird data structure that has the key appended on the end. Perhaps rethink your data and not create this problem for yourself in the first place.
res.data.resultSet.homeTask.forEach((element,index) => {})
second param to function is index you, can use this to identify the second last element by comparing it with total length of array.
hmm you can try with this
res.data.resultSet.homeTask.forEach(element => {
if(!element.task)
return false;
...bla bla bla
}
The map() method creates a new array with the results of calling a function for every array element.
So it creates an array of same length from source array.
What you need is filter()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
Something like this;
const tasks = res.data.resultSet.homeTask.filter((element) => {
const { task, taskDuration, status } = element;
return task && taskDuration && status;
});

Remove objects from array - Two different approaches, two different results when consulting the length of each array

I have two identical arrays: itemsOutput& itemsOutput2
I want to delete those objects in the arrays with attributes.type = "DIMENSION". I have found two different methods for doing so:
Method 1
jQuery.each(itemsOutput, function(i, val) {
if(val.attributes.type == "DIMENSION") // delete index
{
delete itemsOutput[i];
}
});
console.log(itemsOutput.length);
Method 2
metrics = itemsOutput2.filter(function (el) {
return el.attributes.type === "METRIC";
});
console.log(metrics.length);
Although both new arrays seem to have the same number of objects (and in both, all objects with attributes.type = "DIMENSION" are gone), the console shows two totally different values for the length of each array.
Method 1 removes the objects, but length is the same as the original array (although exploring the array in the console I observe that the objects keep their original indexes)
Method 2 not only removes the objects, but it also reassings the indexes successively. And for me, the code seems more clear, so I will stay with this method.
My question is, however, why this happens and if there could be problems if I use the results of method 1 in a loop, for example.
When you delete an array element, the array length is not affected. This holds even if you delete the last element of the array. When the delete operator removes an array element, that element is no longer in the array but the length stays the same.
You will need to use method splice if you want to remove it from the array. For example:
itemsOutput.splice(i, 1);

After using push(), array is logged as a number

I'm trying to get an array of some images to flip through. The first set need to be in descending order, while the second set need to be in ascending order, so I have written this:
var flipArray = [];
function createFlipArray(older, newer){
flipArray = $("#"+older).children();
flipArray = flipArray.get().reverse();
flipArray = flipArray.push($('#'+newer).children());
console.log(flipArray);
loopThroughImages();
}
When I push the second set onto the first set, it logs the array as 4, even though there are 6 items in the whole array.
If I log the array after I populate it with the older children, it returns with HTML objects, which I expect to see after I push the newer children on.
Any suggestions?
.push modifies the array in-place. It does not return a new array, it returns the array's new length.
Array.prototype.push returns the array's new length. It modifies the original array. Remove the flipArray = before it.

push associative array error?

I have to push elements in an associative array from another array after some processing and I'm doing something this:
for(var i in this.aNames) {
var a = this.aNames[i];
// some processing on a
aList[i] = a;
aList.push(i);
}
But it's not giving me the proper array.
EDIT :
Here aNames is an associative array like this
'1232':'asdasdasd',
'6578':'dasdasdas'
...... and so on of about 100 elements.
I'm using for here as I want to do some changes in every element of the array.
Then I'm displaying the result array on the page but it's showing the key value together with the array data.
I.e. it should only display asdasdasd or asdasdasd but it's displaying keys too, like 1232 asdasdasd 6578 dasdasdas.
There are multiple things which may go wrong...
Primarily, make sure that this is pointing to the correct context and that this.aNames is actually returning a complex object (associative array).
Also, what's aList? Is it an array? If it is, push should append your array with the key of the current member (the member's name).
If you want to append the values of the members on your source object, you need to do something like this:
var obj = {name: 'dreas'},
arr = []; // arr is an array
arr.push(obj["name"]); // arr now contains a single element, 'dreas'
In your for..in construct, you are both adding elements to an alleged array (aList) with push but also creating new members on your array (with the subscript notation, aList[i] = "asd" since i in this case (for..in iteration) refers to the member's name).
So, what you need to do is decide if you want to add elements to an array or members to an object, not both.
If you just want to clone an array, use a for loop. If on the other hand you want to clone an object, it's not that trivial because members can also be complex objects containing their own members, and simply doing arr[i] = obj.member will only copy a pointer to arr[i] if member is a complext object, not a value type.
Just to make sure my terminology is understandable:
var anObject = {name: "dreas"},
anArray = [1,2,3];
anObject["name"] <= member (results in "dreas")
anArray[1] <= element (results in 2)

Categories