Sorting Elements of multidimensional Array at a certain Index - javascript

I have an Array of Arrays. My Array is
splitarr[Array0[],Array3[],Array[2],Array[1],Array[4]...]
It is not ordered correctly as you see, I want to order it so it would look something like that.
splitarr[Array0[],Array1[],Array2[],Array3[],Array[4]...]
To understand the whole thing better. There are various "functions" which determine where the array will be sorted. So far I have written a function which orders the array correctly when the "index", where it is ordered incorrectly is 0. But to fully explain how I know where it is ordered incorrectly would take too long to explain.
var dividersecond = 2;
The "divider second", derives from a function. But what is important to know in this context, is that my array is ordered incorrectly at those amount of Positions like this for example:
splitarr[Array2[],Array1[],Array0[],Array3[]...]
var splitarrayindex = 0;
This is the Index of the Array at which the incorrect order starts.
mySplitArray = ReorderArray(dividersecond,splitarrayindex,mySplitArray);
function ReorderArray(Count,Index,Array){
var originalIndex = Index;
for(Index;Index<Count-1;Index++){
var swapIndex= (Count-Index);
var temp = Array[Index];
Array[Index] = Array[swapIndex];
Array[swapIndex] = temp
}
Array.splice(originalIndex,1);
return Array;
}
This function works, as long as the index is 0. Which makes sense.
One of my problems is "Count-1", in the "for-loop". When my Index is "0", and 3 Elements (divider = 2) are ordered incorrectly, I of course need "2" Times of swapping. If my Index is "1", then "Count-1", would mess with this.
There are other things that determine wether my Array will be ordered correctly, for Example determining the Current Index and the Current Swap Index.
All of this and the fact that I am new to Javascript and sorting Arrays, leave me solutionless. If someone could help me with a function that would be awsome!
Here is a quick description of what I wanna do in my Code. (Visualized with Numbers)
2103
(swap at 0 and 2)
0123
Code like this works already because the Index is 0
03214
(Swap Index 1 and Index 3)
01234
How can I make this work?

I think this solved the Problem. Not entirely sure yet. But I will try it with other numbers and Indexes, to see wether it works.
function ReorderArray(Count,Index,Array){
var originalIndex = Index;
for(var i = 0; i<Count-1;i++){
var swapIndex = ((Count+originalIndex)-i);
var temp = Array[originalIndex+i];
Array[originalIndex+i] = Array[swapIndex];
Array[swapIndex] = temp;
}
//delete the position at the original Index
Array.splice(originalIndex,1);
return Array;
}

Related

Include duplicates in for and if loop of array as count number is too small

I'm new to javascript so any help would be greatly appreciated.
What I'm trying to do is cycle through every element in the array and count the number of times the value of an element matches a given condition (even if the value is duplicated).
function loaddata(xml) {
var count = 0;
var i;
var xmlDoc = xml.responseXML;
var z = xmlDoc.getElementsByTagName("group");
if (value1 <= value2) {
for (i = 0; i < (0 + z.length); i++) {
if (z[i].getElementsByTagName("name")[0].childNodes[0].nodeValue == "John") {
count++;
}
}
}
$('#count1').html(count);
};
The count value outputted is too small. I believe the reason for this that the for loop isn't iterating through all elements in the array. When I remove the second if loop and output the count for just the for loop this value is also too small. I believe that the for loop isn't searching through the duplicate elements of the array (i.e. it is ignoring them so that they aren't then fed into the second if loop). Is it possible to specify that the for loop include duplicates?
Do a console.log(z[i].getElementsByTagName("name")) and open your browser's console, and see if that array has data in it.
Then console.log(z[i].getElementsByTagName("name")[0].childNodes) and make sure you have nodes in it.
Also, do you have many <group></group> tags? Because that's what you are selecting with var z = xmlDoc.getElementsByTagName("group");
I hope that helps,

Javascript (dynamic) insert into array, then shift all elements underneath +1

Didn't really found a solution to this for Javascript.
What I need; I want to insert an element into an array, but not really overwrite that element. Rather a 'dynamic' insert. Thus Insert element, then shift all elements underneath it by +1 index.
For instance:
I have an array "14S" "16S" "19S".
I know want to insert "15S".
The resulting array: "14S" "15S" "16S" "19S"
What i tried:
fullName = "15S"
low = 5;
cardsS[low] = fullName;
for (var i = low; i < cardsS.length; i++) {
cardsS[i + 1] = cardsS[i];
}
If you know the position you want to insert the element into:
Use the splice method. It's cheap and works exactly like you want. You can also insert multiple elements at once:
var strings = ["14S", "16S", "19S"];
strings.splice(1,0,"15S");
Result
"14S" "15S" "16S" "19S"
You should also use this solution if you don't want the array to be sorted in a specific way.
If you don't know the position you want to insert the element into:
You will have to resort to a push/sort combination, supplying your own sort algorithm (unless the standard sort is enough)
var strings = ["14S", "16S", "19S"];
strings.push("15S");
strings.sort(function(a, b){
if (a is less than b by some ordering criterion)
return -1;
if (a is greater than b by the ordering criterion)
return 1;
// a must be equal to b
return 0;
});
You can use Array.splice to insert a value:
var arr = ["14S","16S","19S"];
arr.splice(1,0,"15S");
// ^position after which to insert
// ^number of elements to delete (none here)
// ^value to insert ("15S" here)
// => arr is now ["14S","15S","16S","19S"]
If you don't know the position, you could use Array.indexOf to determine it:
var arr = ["14S","16S","19S"];
arr.splice((arr.indexOf('14S')>-1 && arr.indexOf(after)+1 || 0),0,"15S");
// ^use indexOf result if applicable or just insert
// (so, if no position, this turns into unshift ;)
You can create a method for it:
function arrayInsertAfter(array, after, value){
after = array.indexOf(after)>-1 && array.indexOf('14S')+1 || 0;
array.splice(after, 0, value);
return array;
}
// usage
var arr = arrayInsertAfter(["14S","16S","19S"],"14S","15S");
// => ["14S","15S","16S","19S"]
MDN link for Array.splice
you just need to use push() and then sort() functions :
var yourArray = ['14S', '16S', '19S'];
yourArray.push('15S');
yourArray.sort();
You want Array.splice.
This splices a new element at position 1.
arr.splice(1, 0, '155');
Fiddle
What you want is the splice function on the native array object.
var arr = [];
arr[0] = "14S";
arr[1] = "16S";
arr[2] = "19S";
arr.splice(2, 0, "15S");
console.log(arr.join());
The resulting array: 14S, 16S, 15S, 19S
If you do that, you will start at cardsS[5], which will have the value of "fullName".
The fact is that your cardsS as 4 values, so your array is 0 to 3. You can see that your array at position 4 is unbind.
Moreover, if you do cardsS[i + 1], you will be at position 6, which is unbind too.
What you have to do is to:
Check how many item you have in your array (Lenght, Count)
Create a new array with Lenght + 1
Check if your new item is > or < to your first item. If it is >, you have to add your first item, if not you have to add your new item
Do this until your array is full.
If you don't want to do like that, you can use Splice function, just check it, or use a sort function from javascript library.
Hope this can help you !
Try This:
fullName ="15S"
cardsS = ["14S", "16S", "19S"];
for (var k in cardsS)
{
if(parseInt(fullName) < parseInt(cardsS[k])){
cardsS.splice(k,0,fullName)
break;
}
}
:)
if you think is better:
fullName ="15S"
cardsS = ["14S", "16S", "19S"];
for (var k = 0; cardsS.length > k; k++)
{
if(parseInt(fullName) < parseInt(cardsS[k])){
cardsS.splice(k,0,fullName)
break;
}
}
In one of your comments you asked the difference between the splice method and the push+sort method.
Splice just cuts up your array and inserts/deletes values based on index.
Using above mentioned example:
var strings = ["14S", "16S", "19S"];
strings.splice(1,0,"15S");
This will literally place the "15S" on index 1. This is why there is a remark "If you don't know the position you want to insert the element into:"
In which case the push+sort method comes into play. At this point you don't have to go about counting your elements and making sure you place everything at the right location.
You literally just push your "15S" at the end of the array, and then have the sort() automatically sort everything for you.
This, granted that your array is indeed sortable. Some setups don't really allow you to sort your arrays (Like colors sorted by color in the rainbow ... you can't just sort them using sort()).
In this case KooiInc's response comes into play. At this point you know where your item needs to be. 15S comes after 14S, so you search for 14S, get that index, and use that index to splice.
At this point you still have to calculate yourself what element 15S will have to go after - in my rainbow example you'll have to actively remember where you want to 'insert' which color based on which colors are in your array at this moment.
In your example the values seem to be suited for normal sorting, so i would go with the Push+sort approach a few people mentioned.
var arr = [1,2,4,5,6];
var element = 3, pos=3;
for(i=arr.length-1; i>=pos-1; i--){
arr[i+1]=arr[i];
}
arr[pos-1]=element;
console.log(arr);

How to keep Javascript array sorted, without sorting it

I have a Node.js application where I have to very often do following things:
- check if particular array already contains certain element
- if element does exist, update it
- if element do not exist, push it to the array and then sort it using underscore _.sortBy
For checking if the element already exists in the array, I use this binary search function:
http://oli.me.uk/2013/06/08/searching-javascript-arrays-with-a-binary-search/
In this way, when the size of the array grows, the sorting becomes slower and slower.
I assume that the array size might grow to max 20 000 items per user. And eventually there will be thousands of users. The array is sorted by a key, which is quite a short string. It can be converted into integer if needed.
So, I would require a better way to keep the array sorted,
in stead of sorting it every time new element is pushed onto it.
So, my question is, how should/could I edit the binary search algorithm I use, to enable me to
get the array index where the new element should be placed, if it doesn't already exist in the array?
Or what other possibilities there would be to achieve this. Of course, I could use some kind of loop that would start from the beginning and go through the array until it would find the place for the new element.
All the data is stored in MongoDB.
In other words, I would like to keep the array sorted without sorting it every time a new element is pushed.
It's easy to modify this binaryIndexOf function to return an index of the next element when no matches found:
function binaryFind(searchElement) {
'use strict';
var minIndex = 0;
var maxIndex = this.length - 1;
var currentIndex;
var currentElement;
while (minIndex <= maxIndex) {
currentIndex = (minIndex + maxIndex) / 2 | 0; // Binary hack. Faster than Math.floor
currentElement = this[currentIndex];
if (currentElement < searchElement) {
minIndex = currentIndex + 1;
}
else if (currentElement > searchElement) {
maxIndex = currentIndex - 1;
}
else {
return { // Modification
found: true,
index: currentIndex
};
}
}
return { // Modification
found: false,
index: currentElement < searchElement ? currentIndex + 1 : currentIndex
};
}
So, now it returns objects like:
{found: false, index: 4}
where index is an index of the found element, or the next one.
So, now insertion of a new element will look like:
var res = binaryFind.call(arr, element);
if (!res.found) arr.splice(res.index, 0, element);
Now you may add binaryFind to Array.prototype along with some helper for adding new elements:
Array.prototype.binaryFind = binaryFind;
Array.prototype.addSorted = function(element) {
var res = this.binaryFind(element);
if (!res.found) this.splice(res.index, 0, element);
}
If your array is already sorted and you want to insert an element, to keep it sorted you need to insert it at a specific place in the array. Luckily arrays have a method that can do that:
Array.prototype.splice
So, once you get the index you need to insert at (you should get by a simple modification to your binary search), you can do:
myArr.splice(myIndex,0,myObj);
// myArr your sorted array
// myIndex the index of the first item larger than the one you want to insert
// myObj the item you want to insert
EDIT: The author of your binary search code has the same idea:
So if you wanted to insert a value and wanted to know where you should
put it, you could run the function and use the returned number to
splice the value into the array.
Source
I know this is an answer to an old question, but the following is very simple using javascripts array.splice().
function inOrder(arr, item) {
/* Insert item into arr keeping low to high order */
let ix = 0;
while (ix < arr.length) {
//console.log('ix',ix);
if (item < arr[ix]) { break; }
ix++;
}
//console.log(' insert:', item, 'at:',ix);
arr.splice(ix,0,item);
return arr
}
The order can be changed to high to low by inverting the test

I'm having trouble writing a recursive function in JavaScript - it doesn't seem to "fall back" to the lesser depth correctly

var diceToRoll = [2,2];
var diceRolled = new Array();
function recurse(diceToRoll, diceRolled) {
roll = diceToRoll[0]
diceLeftToRoll = diceToRoll;
diceLeftToRoll.shift();
for(loop=1; loop<(roll+1); loop++) {
result = diceRolled;
result.push(loop);
if(diceLeftToRoll.length == 0) {
console.log(result);
result.pop();
} else {
recurse(diceLeftToRoll, result);
}
}
}
recurse(diceToRoll, diceRolled);
I'm trying to write a recursive function which prints the possible results of any number of dice. For example, a dd100 (diceToRoll = [6, 10, 10, 100])(diceToRoll = [6, 6, 6, 6, 6]) etc. In the example I have used the simplest case(or two 2-sided dice).
I expected the results to be [1,1], [1,2], [2,1], [2,2] however it only logs [1,1], [1,2]. This is the same with any number or type of dice - only the deepest level of recursion works correctly.
I figure I'm missing something obvious in the logic of it / or misunderstanding variable scope in JavaScript, but I'm just really struggling to get my head around it.
Edit 1 (To make explanation of program's purpose clearer)
The programs purpose is to list all possible values on any number of dice. So a dice 6 implies the range of values 1..6. Likewise, a two-sided dice, 2, implies the range of values 1..2. So for two two-sided dice in the example (diceToRoll[2,2]) the possible values are 1,1 1,2 2,1 and 2,2 - which is what should be returned.
There are several issues with your code:
Use var keyword in order to define local variables.
Assigning array to another variable not copies its content, just reference to the same array. Use Array.slice() if you want to clone array.
Here is a fixed function:
var diceToRoll = [2,2],
diceRolled = [];
function recurse(diceToRoll, diceRolled) {
var roll = diceToRoll[0],
diceLeftToRoll = diceToRoll.slice(1),
loop,
result;
for(loop=1; loop<=roll; loop++) {
result = diceRolled.slice(0);
result.push(loop);
if(diceLeftToRoll.length === 0) {
console.log(result);
result.pop();
} else {
recurse(diceLeftToRoll, result);
}
}
}
recurse(diceToRoll, diceRolled);
NOTE
diceToRoll = diceToRoll.slice(1)
is equivalent to
diceToRoll = diceToRoll.slice(0);
diceToRoll.shift();
Fiddle here: http://jsbin.com/isebef/1/edit
You must declare "roll" (and other local variables) with var.
function recurse(diceToRoll, diceRolled) {
var roll = diceToRoll[0]
var diceLeftToRoll = diceToRoll;
diceLeftToRoll.shift();
for(var loop=1; loop<(roll+1); loop++) {
var result = diceRolled;
result.push(loop);
if(diceLeftToRoll.length == 0) {
console.log(result);
result.pop();
} else {
recurse(diceLeftToRoll, result);
}
}
}
Without var, "roll" and "loop" are global.
I'm not sure what the point of "result" is; it's just a reference to the "diceRolled" array, so I'm not sure why you wouldn't just use that.
edit — I'm not sure exactly what your code is trying to do here, but another significant problem is this:
var diceLeftToRoll = diceToRoll;
diceLeftToRoll.shift();
When you make an assignment like that of a value that's a reference to an array, you do not make a copy of the array. Thus both variables refer to the same array object, and the first element will be removed from it. If you instead make "diceLeftToRoll" a copy of the other array, then things work differently:
var diceLeftToRoll = diceToRoll.slice(1); // copy all but 1st element
I don't think the whole thing will work, however, because I now think that the "result" variable was an attempt to do something similar.
edit again Here is an alternative version that returns results in a list. This one avoids making copies except for the final entries added to the result.
function allRolls( dice ) {
var list = [], rolled = [];
function roll( dn ) {
var dp = rolled.length;
for (var dv = 1; dv <= dice[dn]; ++dv) {
rolled[dp] = dv;
if (dn < dice.length - 1)
roll(dn + 1)
else
list.push(rolled.slice(0));
}
rolled.length = dp;
}
if (dice.length) roll(0);
return list;
}
allRolls([3, 3, 3]);
The function involves an inner function that does all the work. It's passed the index in the "dice" list of a dice to roll; initially, that's 0.
The function keeps track of two other lists: the accumulated possible rolls, and an array representing the "rolled so far" for use by the recursive inner function.
At each recursive level, the function iterates through the faces of the current dice (that is, dice[dn]). Each iteration places that dice value in a slot at the end of the "rolled" array; the same slot is used for each iteration. Now, if the loop notices that "dn" represents the last dice in the list, then it makes a copy of the "rolled" array and adds it to the result list. If not, then it makes a recursive call, passing the next dice index down.
The outer function then just checks to see if there are any dice to roll, and rolls them if so. It returns the accumulated list.

Create multiple arrays based on frequency of coordinates in an array

Using JavaScript, I'd like to split one big array of coordinates into smaller arrays based on coinciding points. I am not 100% sure how to write the following in code but it describes what I'm attempting to achieve:
Iterate through the array
var A = [(1,2)(1,3)(2,3)(9,10)(9,11)(10,11)];
Combine the pairs that contain any matching/identical coordinate points:
var B = (1,2)(1,3)(2,3)
var C = (9,10)(9,11)(10,11)
Combine the matching/identical points and create new, smaller arrays from the combinations in point #2
var D = [1,2,3]
var E = [9,10,11]
Can I get help please?
Working answer: http://jsfiddle.net/y3h9L/
OK, so if I understand the requirement A is a one-dimensional array that is assumed to have an even number of elements in x,y pairs.
A = [1,2, 1,3, 2,3, 9,10, 9,11, 10,11]
// output should be
[ [1,2,3], [9,10,11] ]
// but if you add an extra pair that links the two halves, say add 2,11
A2 = [1,2, 1,3, 2,3, 9,10, 9,11, 10,11, 2,11]
// then all are related so output should be
[ [1,2,3,9,10,11] ]
I've made no effort to pretty-up or optimise the following code, but it works:
// single dimensional array of x,y pairs
var A = [1,2, 1,3, 2,3, 9,10, 9,11, 10,11];
// create a working copy of A so that we can remove elements
// and still keep the original A intact.
var workingCopy = A.slice(0, A.length),
matchedPairs = [],
currentMatches,
finalCombinations = [],
x, y, i, j,
tempArray;
while (workingCopy.length > 0) {
currentMatches = [];
currentMatches.push([workingCopy.shift(),workingCopy.shift()]);
workingCopyLoop:
for (x=0,y=1; x < workingCopy.length;) {
for (i=0; i < currentMatches.length; i++){
if (workingCopy[x] === currentMatches[i][0]
|| workingCopy[y] === currentMatches[i][1]) {
currentMatches.push([workingCopy.shift(),workingCopy.shift()]);
// go back to the beginning of workingCopyLoop
x=0;
y=1;
continue workingCopyLoop;
}
}
x += 2;
y += 2;
}
matchedPairs.push(currentMatches);
}
for (i=0; i<matchedPairs.length; i++){
tempArray = [];
for (j=0; j<matchedPairs[i].length; j++) {
// I assume you have a new enough version of JS that you have Array.indexOf()
if (-1 === tempArray.indexOf(matchedPairs[i][j][0]))
tempArray.push(matchedPairs[i][j][0]);
if (-1 === tempArray.indexOf(matchedPairs[i][j][1]))
tempArray.push(matchedPairs[i][j][1]);
}
finalCombinations.push(tempArray);
}
for (i=0; i<finalCombinations.length; i++)
console.log(finalCombinations[i]);
// console.log shows that finalCombinations = [ [1,2,3], [9,10,11] ]
If it's not obvious how this works, follow it through with a debugger and/or pencil and paper.
I must say your question is rather unclear, but i think i got it.
In other words what you're saying is:
I have an array containing a bunch of numbers, logically they represent coordinates, it's not that the coordinates are subarrays inside the master array, is just looking them 2 by 2, but it's a linear array.
What you want is something that detects coordinates that are adjacent and generate a new array containing them.
After that you want to go thru the new arrays and generate new arrays containing unique-elements.
Well that's the question, now the answer. First, the second point depends on how far you want to go, i'm thinking it's anormal grid of x,y coordinates, but how adjacent you want to go? The following just applies to the inmediate adjacent, up to 8 points can be adjacent to a single point.
[1,1][2,1][3,1]
[1,2][2,2][3,2]
[1,3][2,3][3,3]
May that be a representation of the grid, if your master array has the [2,2] coordinate, you want to build an array that begins with that one and all adjacents you find, lets say like master array has [3,2], then you want to add it to the subarray of [2,2].
I'm really not writing the code i'm just gonna explain sorts of algorithm you could use.
To build the second point arrays, lets call them Adjacents Arrays (AA) you could:
First coordinate will always build the first AA
To find adjacents you will cycle thru the master array and perform an "Adjacency Check" to every coordinate which would be: second x == ( first x-1, x or x+1) AND second y == ( first y-1, y or y+1), if it passes then pop/push, if not... next.
In case you finish cycling thru the master array means that AA is complete, and you have to start a new AA with the next coordinate.
Repeat until master array is empty.
Then to create the unique-element-array is quite a simple cycle, i wrote a similar function that does something like that but it creates an array with the element and how many times it appears in the array (instances):
function uniqueCnt( ori) { // agroups and counts unique elements of an array, scrubs '' elements
var res = []; // resulting array, ori parameter stands for original array
for( let cntA = 0; cntA < ori.length; cntA++) {
for( cntB = 0; cntB < res.length; cntB += 2) if( ori[cntA] == res[cntB]) { res[cntB + 1]++; break; } // if it matches means it's another instance then increase that element count
if( cntB == res.length && ori[cntA] != '') res.push( ori[cntA], 1); // New element found then push it and start count
}
return res; // returns the agrouped array 0:element 1:instances...
}
If you don't want a count of instances, then you would need an even simpler function, you could try modify this one.

Categories

Resources