How to sort pushed array by id? - javascript

I have two arrays. First one which comes from response is divided by pagination. When i remove items from second array, they should be placed back sorted by id in first array, instead they go to bottom of array and i have to scroll down to find certain element. This is my code for pushing elements from array vm.feeds to vm.rationList:
function addAll() {
var mList = JSON.parse(JSON.stringify(vm.feeds))
for (var i = 0; i < mList.length; i++) {
mList[i].is_selected = false;
vm.rationList.push(mList[i]);
}
vm.feeds = [];
vm.rationListSafe = vm.rationList;
if(vm.feeds.length == 0){
vm.currentPageMaster++;
vm.isPage = true;
vm.disableScroll = true;
getFeedsByTeam(vm.selectedTeam);
}
}
Second part is how i remove elements from array vm.rationList and push them back to first array - vm.feeds:
function removeAll() {
for (var i = 0; i < vm.rationList.length; i++) {
vm.feeds.push(vm.rationList[i])
}
vm.rationList = []
}
In removeAll() i have to add additional check which will sort them by ID on push. Any idea for this?

The Array.push method add item to the end of your list.
To put an element at a given position in an array, you may prefer using Array.splice.
First argument is the index, second is the number of items to delete (in your case, 0), and a third argument would be the item to add at the given index.
With that, you can replace the push in removeAll by
vm.feeds.splice(correctIndex, 0, vm.rationList[i]);
Question is : what is correctIndex ?
Well, for that, there might be many solutions depending on your architecture, but a simple one could be to loop on vm.feeds to find the first item with an id that is not lower than the one you want to add:
var correctIndex = 0;
for(var item of vm.feeds) {
if (item.id >= vm.rationList[i].id) {break;}
else {correctIndex++;}
}

vm.feeds.sort(function(a, b) {
return parseFloat(a.id) - parseFloat(b.id);
});
This is the solution I found and it works

Related

How do i push an array[i] to another array

Basically i have to create a quiz with 3category. each with 5questions.
I would have to push the selected category-questions into this new array from the array with all the questions. I am unable to do so.
pushSelectedQuestion() {
for (var i = 0; i < this.getNumberOfQuestion; i++) {
if (usercategory == questionPool[i].category) {
mcqSelected.push(questionPool[i])
return mcqSelected;
}
}
}
usercategory = input from user.
if user chooses category 1.
if (1 == questionPool[1].category) (if it matches the category) then it will be pushed.
This is the part which i cant do
Well, from the information you've provided, there's one main issue here - the return statement is definitely shortcutting the loop - so even if you have everything else right, you'll only ever get the first matching question. The rest will have been cut out by the return statement, which stops the function and returns the value.
pushSelectedQuestion() {
for (var i = 0; i < this.getNumberOfQuestion; i++) {
if (usercategory == questionPool[i].category) {
mcqSelected.push(questionPool[i])
// the below line is causing this loop to end after the first time through the list.
// Remove it and then put a console.log(mcqSelected);
// here instead to see the value during each iteration of the loop.
return mcqSelected;
}
}
}
There are a lot of ways to accomplish what you want to do here though. For example, you could just use the javascript Array.filter method like so
let selectedQuestions = questionPool.filter(question => question.category == userCategory)
Maybe I am not understanding your question correctly, but can't you use nested arrays. If the questions are categorized beforehand that is.

How to detect duplicate characters in an Array, and create an argument accordingly?

Good evening, I attempting to detect duplicate characters in a string. More specifically, I am trying to find up to two different duplicates within an Array. If there is one duplicate, add a sub-string, and if there is another duplicate, add a different sub-string. Is there any way to do this?
Here is some example code I have so far:
var CodeFieldArray = ["Z80.0", "Z80.1", "Z80.0", "Z70.4"];
/* We have an array here used to create the final string at the end of the
code. It is a dummy array with similar variables in my actual code. For
reference sake, there may be only one object in the array, or 7 total,
depending on the user's input, which is where the duplicate detection should
come in, in case the user enters in multiples of the same code. */
var i, Index;
for (i = 0, L = 0; i < CodeFieldArray.length; i++) {
Index = CodeFieldArray[i].indexOf(CodeFieldArray[i]);
if(Index > -1) L += 1;
Extra0 = CodeFieldArray.indexOf("Z80.8");
Extra1 = CodeFieldArray.indexOf("Z80.9");
if(L >= 2 && Extra0 == -1) CodeFieldArray.push("Z80.8");
Extra0 = CodeFieldArray.indexOf("Z80.8");
if(L >= 4 && Extra0 != -1 && Extra1 == -1) CodeFieldArray.push("Z80.9");
console.println(Extra0);
}
/*^ we attempted to create arguments where if there are duplicates
'detected', it will push, "Z80.8" or, "Z80.9" to the end of the Array. They
get added, but only when there are enough objects in the Array... it is not
actually detecting for duplicates within the Array itself^*/
function UniqueCode(value, index, self) {
return self.indexOf(value) === index;
}
CodeFieldArray = CodeFieldArray.filter(UniqueCode);
FamilyCodes.value = CodeFieldArray.join(", ");
/* this is where we turn the Array into a string, separated by commas. The expected output would be "Z80.0, Z80.1, Z70.4, Z80.8"*/
I have it to where it will add "Z80.8" or "z80.9" if they are not present, but they are being added, only if there are enough objects in the Array. My for-loop isn't detecting specifically the duplicates themselves. If there was a way to detect specifically the duplicates, and create an argument based off of that, then we would be doing grand. The expected output would be "Z80.0, Z80.1, Z70.4, Z80.8"
You can use Set and forEach and includes
var CodeFieldArray = ["Z80.0", "Z80.1", "Z80.0", "Z70.4"];
let unique = [...new Set(CodeFieldArray)];
let match = ['Z80.8','Z80.9'];
let numOfDup = CodeFieldArray.length - unique.length;
if(numOfDup){
match.forEach(e=>{
if(!unique.includes(e) && numOfDup){
unique.push(e);
numOfDup--;
}
})
}
console.log(unique.join(','))
So the idea is
Use Set to get unique values.
Now see the difference between length of original array and Set to get number of duplicates.
Now will loop through match array and each time we push item from match array into unique we reduce numOfDup by so ( to handle case where we have only one duplicate or no duplicate ).
In the end join by ,
You could do something like this:
var uniqueArray = function(arrArg) {
return arrArg.filter(function(elem, pos,arr) {
return arr.indexOf(elem) == pos;
});
};
uniqueArray ( CodeFieldArray )

How to efficiently group items based on a comparison function?

I have a list of items and a comparison function f(item1, item2) which returns a boolean.
I want to generate groups out of these items so that all items in a same group satisfy the condition f(itemi, itemj) === true.
An item can be included in several groups. There is no mimimum size for a group.
I am trying to write an efficient algorithm in javascript (or other language) for that. I thought it would be pretty easy but I am still on it after a day or so...
Any pointer would be highly appreciated!
(the max size of my items array is 1000, if it helps)
OK, so here's how I did it in the end. I am still unsure this is completely correct but it gives good results so far.
There are two phases, first one is about creating groups that match the condition. Second one is about removing any duplicates or contained groups.
Here's the code for the first part, second part if quite trivial:
for(index = 0; index < products.length; index++) {
existingGroups = [];
seedProduct = products[index];
for(secondIndex = index + 1; secondIndex < products.length; secondIndex++) {
candidateProduct = products[secondIndex];
if(biCondition(seedProduct, candidateProduct)) {
groupFound = false;
existingGroups.forEach(function(existingGroup) {
// check if product belongs to this group
isPartOfGroup = true;
existingGroup.forEach(function(product) {
isPartOfGroup = isPartOfGroup && biCondition(product, candidateProduct);
});
if(isPartOfGroup) {
existingGroup.push(candidateProduct);
groupFound = true;
}
});
if(!groupFound) {
existingGroups.push([candidateProduct]);
}
}
}
// add the product to the groups
existingGroups.forEach(function(group) {
group.push(seedProduct);
if(group.length > minSize) {
groups.push(group);
}
});
}
Instead of items I use products, which is my real use case.
The bicondition tests for f(item1, item2) && f(item2, item1). To speed up and avoid duplication of calculus, I created a matrix of all condition results and I use this matrix in the biCondition function.

Array.splice inside a for loop causing errors

im using Angular ng-repeat to display $scope.currentMessageList array
i also have a remove button bound via ng-click to the remove function, which looks like this:
remove: function () {
for (var i = 0; i < 25; i++) {
var index = i;
$scope.currentMessageList.splice(index, 1);
console.log($scope.currentMessageList.length + 'left');
}
}
There are 25 items in this collection, when I call the remove function,
I get this output:
24left
23left
22left
21left
20left
19left
18left
17left
16left
15left
14left
13left
13times X 12left
If I replace the for loop with angular.forEach
I get "12 left" only once, still it doesn`t remove more than 13 items
Ive also tried to use angular.apply, than I get digest already in progress error
Performing a splice while iterating through an array is a bad idea.
You should replace
for( var i = 0; i < 25; i++ ){
var index = i;
$scope.currentMessageList.splice( index, 1 );
console.log($scope.currentMessageList.length + 'left');
}
by a simple
$scope.currentMessageList.splice( 0, 25 );
You're removing items while walking the array.
When you reach half of the array you've already removed half the items, so you won't remove anything else.
You can fix this either by always removing the first item or by iterating backwards from 24 towards 0.
When you remove array items in loop, indexes get shifted too. As the result you can iterate over only the half of them. This is the issue here.
If you want to clear 25 first items you can remove them with Array.prototype.shift method instead. In this case it will remove the first element of the array 25 times, giving you expected result:
remove: function () {
for (var i = 0; i < 25; i++) {
currentMessageList.shift();
}
}
When you splice the array.. the length of the array changes.
When you are trying to remove the element at index 13, the length is 12 only.
Hence it is not removed.
Instead of splice, try shift();
You don't need to iterate over your array to remove all the items. Just do this:
remove : function(){
$scope.currentMessageList = [];
}
Check out this answer also. There are others way to achieve this that are also valid.

Using Jquery Splice

I am trying to remove an item from an Array using Splice method.
arrayFinalChartData =[{"id":"rootDiv","Project":"My Project","parentid":"origin"},{"1":"2","id":"e21c586d-654f-4308-8636-103e19c4d0bb","parentid":"rootDiv"},{"3":"4","id":"deca843f-9a72-46d8-aa85-f5c3c1a1cd02","parentid":"e21c586d-654f-4308-8636-103e19c4d0bb"},{"5":"6","id":"b8d2598a-2384-407a-e2c2-8ae56c3e47a2","parentid":"deca843f-9a72-46d8-aa85-f5c3c1a1cd02"}];
ajax_delete_id = "e21c586d-654f-4308-8636-103e19c4d0bb,deca843f-9a72-46d8-aa85-f5c3c1a1cd02,b8d2598a-2384-407a-e2c2-8ae56c3e47a2";
$.each(arrayFinalChartData, function (idx, obj) {
var myObj = obj.id;
if (ajax_delete_id.indexOf(myObj) >= 0) {
var vararrayFinalChartDataOne = arrayFinalChartData.splice(idx, 1);
}
});
console.log(arrayFinalChartData);
Please check at : http://jsbin.com/deqix/3/edit
Note : It does not complete the "last leg " of the loop. That means if I have 4 items, then it successfully executes 3 items. Same goes for 6,7...items.
I need to "REMOVE" few items and "PRESERVE THE BALANCE" in an array.
You can use for loop instead of $.each function:
alert('length before delete ' + arrayFinalChartData.length);
for (var i = arrayFinalChartData.length - 1; i >= 0; i--) {
id = arrayFinalChartData[i].id;
if(ajax_delete_id.indexOf(id) > -1){
arrayFinalChartData.splice(i, 1);
}
};
alert('length after delete ' + arrayFinalChartData.length);
Demo.
Complete edit :
After researching a bit, and console.logging a lot, I finally found where the issue is coming from ! It's actually quite simple, but very sneaky !
Theoretical explanation :
You are calling the splice function with the variable "idx", but remember that the splice function remaps / reindexes your array ! So, each time you splice the array, its size decreases by one while you're still inside the $.each function. The splice messes up jQuery indexation of your array, because jQuery doesn't know that you're removing elements from it !
Iterative explanation :
$.each function starts, thinking your array has 4 elements, which is true, but only for a while. First loop, idx = 0, no splice. Second loop, idx = 1, splice, which means that your array has now 3 elements left in it, reindexed from 0 to 2. Third loop, idx = 2, splice, which means your array has now two elements left in it, but $.each continues ! Fourth loop, idx = 3, js crashes, because "arrayFinalChartData[3]" is undefined, since it was moved back each time the array got spliced.
To solve your problem, you need to use a for loop and to start analyzing the array from the end, not from the beginning, hence each time you splice it, your index will decrease as well. And if you want to preserve balance, just push the removed items into an array. Remember that you are analyzing the array from the end, so items pushed into the "removedItems" array will be in reverse order. Just like this :
var removedItems = new Array();
for (var i = arrayFinalChartData.length - 1; i >= 0; i--) {
var myObj = arrayFinalChartData[i].id;
if (ajax_delete_id.indexOf(myObj) >= 0) {
removedItems.push(arrayFinalChartData.splice(i, 1)[0]);
}
}
console.log(arrayFinalChartData);
console.log(removedItems);
And a working demo (inspect the page, observe the console and click "Run") :
http://jsfiddle.net/3mL6C/3/
I will not give credit to myself for this answer, thanks to another similar thread for giving me a hint.
Your problem here is that when the $.each is set up, it's expecting a certain length of object, which you are then changing. You need to loop in a way that respects the dynamic length of the object.
var i = 0;
while (i < arrayFinalChartData.length) {
var myObj = arrayFinalChartData[i].id;
if (ajax_delete_id.indexOf(myObj) >= 0) {
// current item is in the list, so remove it but KEEP THE SAME INDEX
arrayFinalChartData.splice(i, 1);
} else {
// item NOT in list, so MOVE TO NEXT INDEX
i++
}
}
console.log(arrayFinalChartData);
Demo

Categories