JS Multidimensional Array with No Fixed Size - javascript

In my program I have:
an array currentIndex that will look something like [1, 2, 2]
a multidimensional array directions that looks like [1, [2, 0, [2, 3, -]] 1]
How can I loop through the first one in such a way that I can access directions[1][2][2] (turn the first array in the indexes of the second) ?

To access directly one value you could use vector[1][2], but remember that the array index starts with 0.
But, if you want to walk through the vector you need a recursive function:
function printRecursiveArray(value, c){
for(c=0; c<value.length; c++){
if (typeof value[c] !=='object'){
console.log(value[c]);
}else{
printRecursiveArray(value[c],0);
}
}
}
var vector = [1,[1,2,3],2,3];
printRecursiveArray(vector,0);
console.log('vector[1][2]:' + vector[1][2]);// To access directly
So, your array could have any dimension, but you still print the elements.

From what I understand you want to iterate through the first array where each value in the first array is the index you want to access in the multidimensional array. The following recursive function should work:
//index: Array of indexes
//arr: The mutlidimensional array
function accessMutliArr (index, arr) {
if (index.length === 1)
return arr [ index ];
else {
var currentIndex = index.splice(0, 1);
return accessMutliArr (index , arr [ currentIndex ]);
}
}

If you want to loop over a multidimensional Array then the process can look like:
for(var i in directions){
for(var n in direction[i]){
for(var q in directions[i][n]){
var innerIncrement = q, innerValue = directions[i][n][q];
}
}
}
Take into account that a for in loop will automatically make your indexes Strings. The following is a fail proof way to do the same thing, with some other help:
for(var i=0,l=directions.length; i<l; i++){
var d = directions[i];
for(var n=0,c=d.length; n<c; n++){
var d1 = d[n];
for(var q=0,p=d1.length; q<p; q++){
var innerIncrement = q, innerValue = d1[q];
}
}
}
When you do a loop like either of the above, imagine that each inner loop runs full circle, before the outer loop increases its increment, then it runs full circle again. You really have to know what your goal is to implement these loops.

Related

How to work with multidimensional array when the number of dimension is variable?

Hello stackoverflow members.
I come with the following problem:
To start we have
var myArray = [[array1],[array2],[array3],[arrayN],...];
where each array is filled with a known number of strings such as
var array1 = ["a","b"], array2 = ["1","2"], array3=["&","é"];....
and so on.
I'm looking for a method to get this result:
expected result ===> a1&;a1é;a2&;a2é;b1&;b1é;b2&;b2é; ....
If the number of dimension were fixed I could use for loops to iterate and build the result, BUT here the problem is that I want to be able to enter N arrays in the main array myArray and by doing so, I change the depth of the nested loops.
If not do you have some ideas to put me on the track of the solution to this?
Thanks!
EDIT by the way this is what i experimented:
for (i=0; i<myArray[0].length; i++){
for (var j =0; j<myArray[1].length; i++){
for(var k = 0; k<myArray[2].length; k++{
console.log(i+j+k);
}
}
}
BTW i can't find a way to describe a function which would nest N for loops where N is myArray.length + 1 (the number of arrays in myArray).
EDIT: i found an iterative way of doing it and wanted to share the solution:JSFiddle
To get a flat list of all cells, something like the following recursive function should work (if you have a non-empty array of arrays, and all array items are strings):
function makeFlatList(inputArray) {
if (inputArray.length == 1) { // if this array has only one array inside
return inputArray[0]; // return the array inside
} else {
var outArr = [];
var arrayShifted = inputArray.slice(1); // remove first subarray from inputarray
var arrayShiftedFlat = makeFlatList(arrayShifted); // recursive call
for (var i=0; i<inputArray[0].length ; i++) { // loop over first array
for (var j=0; j<arrayShiftedFlat.length; j++) {
outArr.push(inputArray[0][i]+arrayShiftedFlat[j]); // add items to outArr
}
}
return outArr;
}
}
Working JSBin here

Combining elements of 2 dimentional array

I have an JavaScript array:
var arr = [["A",["05",90]],["A",["04",240]],["A",["03",235]],["B",["00",123]],["B",["01",234]]];
I want final array to look like:
var final = [["A",[["05",90],["04",240],["03",235]]],["B",[["00",123],["01",234]]]];
The final array is formed by combining all the 2nd element of 2 dimensional array when the 1st element matches.
Please advice how can this be achieved in JavaScript
Object keys are generally the easiest way to create groups like this
var tmp = {}; // temporary grouping object
// loop over data
arr.forEach(function (item) {
// check if group started
if (!tmp.hasOwnProperty(item[0])) {
tmp[item[0]] = [];
}
// push data to group
tmp[item[0]].push(item[1]);
});
// map temp object to results array
var results = Object.keys(tmp).map(function (key) {
return [key, tmp[key]];
});
DEMO
If you start with the array you gave:
var arr = [["A",["05",90]],["A",["04",240]],["A",["03",235]],["B",["00",123]],["B",["01",234]]];
then create a new array to store the values:
var final = [];
and simply combine all of the third-level elements (such as ["05",90] and ["01",234]) of each second-level ones (such as "A" and "B") by looping through the array:
for(var i = 0; i < arr.length; i++) {
var found = false;
for(var j = 0; j < final.length; j++) {
if(arr[i][0] == final[j][0]) {
final[j][1].push(arr[i][1]);
found = true;
break;
}
}
if(!found) {
final[final.length] = [arr[i][0], [[arr[i][1][0], arr[i][1][1]]]];
}
}
This is essentially a sorting method: if the "key" is equal to one in the final array, then it adds it to that one. If not, then appends it to the end of final.
Here's the working example on JSFiddle: link.
This outputs the array:
["A", [["05", 90], ["04", 240], ["03", 235]]], ["B", [["00", 123], ["01", 234]]]
as requested.
Also, as #PaulS commented, it would be recommended to use Objects instead as Strings, to make them Key-Value pairs. But in my answer I stuck with arrays.

When passing an array through a function, can I call the function after?

I have to save an array of integers to a variable and then use a for loop to loop through each element in the array where I pass the array into a doubling function then I save the original number and the doubled number as key-value pairs in an object. I am currently stuck and here is my code:
var myArray = [1, 2, 3, 4, 5];
for (i=0; i < myArray.length; i++)
{
myArray[i];
}
var double = function(number)
{
return number * 2;
};
var double = {i: double(myArray[i])};
Just do a loop to initialize the object:
var i = 0;
var doubleObject = {};
for( i = 0 ; i < myArray.length ; i++){
doubleObject[myArray[i]] = doubleFunction(myArray[i]);
}
double is a reserved word by the way. You should not use it.
You have to loop the Array to do something with every element in the Array.
There a couple of errata in your code:
you are doing nothing with myArray[i]; in the loop.
you assigning the variable double twice.
i is not defined in the last piece of code.
A clean way to do this is:
var myDoubleArray = myArray.map(function(arrItem){
return double(arrItem);
})
Edit:
After reading comments/question thoroughly I think Paul D. has your answer ;)
yet another variant with reduce
myArray.reduce(function(ac,item){
return ac[item] = doubleFunction(item), ac;
}, {})

Javascript: How to clear undefined values from an array

I'm trying to loop through an array and delete and skip the elements until only one is existing. i've tried splicing but it messes up my loop because the element from arr[1] then becomes arr[0] etc.
Let's say there are 10 people. I'd like to remove person 1 then keep person 2 then remove person 3 and keep person 4. This pattern will go on until only one is left.
any kind of help will do.
Filter the falsy items:
var a=[1,2,"b",0,{},"",NaN,3,undefined,null,5];
var b=a.filter(Boolean); // [1,2,"b",{},3,5]
you should not change the collection during the iterating, not just JavaScript but all language, define a new array and add those ones you want to delete in it, and iterate that one later to delete from first one.
When you splice, just decrement your loop index.
There were lots of good suggestions, I'll post the code for the different options and you can decide which to use
Decrement index when splicing
http://jsfiddle.net/mendesjuan/aFvVh/
var undef;
var arr = [1,2, undef, 3, 4, undef];
for (var i=0; i < arr.length; i++) {
if ( arr[i] === undef ) {
arr.splice(i,1);
i--;
}
}
Loop backwards http://jsfiddle.net/mendesjuan/aFvVh/1/
var undef;
var arr = [1,2, undef, 3, 4, undef];
for (var i=arr.length - 1; i >=0; i--) {
if ( arr[i] === undef ) {
arr.splice(i,1);
}
}
Copy to new array http://jsfiddle.net/mendesjuan/aFvVh/2/
var undef;
var arr = [1,2, undef, 3, 4, undef];
var temp = [];
for (var i=0; i < arr.length; i++) {
if ( arr[i] !== undef ) {
temp.push(arr[i])
}
}
arr = temp;
Use filter which is just a fancy way to create a new array
var undef;
var arr = [1,2, undef, 3, 4, undef];
arr = arr.filter(function(item){
return item !== undef;
});
At the end of all those examples, arr will be [1,2,3,4]
Performance
IE 11, FF and Chrome agree that Array.splice is the fastest. 10 times (Chrome), 20 times (IE 11) as fast as Array.filter. Putting items into a new array was also slow when compared to Array.slice. See
http://jsperf.com/clean-undefined-values-from-array2
I am really surprised to see IE lead the pack here, and to see Chrome behind FF and IE. I don't think I've ever run a test with that result.
Loop backwards. (Removing items will thus not affect the indexes of elements not yet processed.)
If by any chance you're using CoffeeScript then to remove undefined from Array do this
values = ['one', undefined]
values = (item for item in values when item != undefined)
values
/* => ['one'] */
Surprisingly, nobody have answered the best and correct way:
Create new array
Iterate on the old array and only push the elements you want to keep to the new array
some credit goes to #nnnnnn comment
Not gathering exactly what you are trying to achieve, but I feel you are relying on the position index of an item in the array to continue with your program. I would in this case suggest a hashed array, i.e., a Key<>Value pair array.
In which case, arr["2"] always points at the item you had placed in it originally. Thus you can logically/numerically loop through, while not worrying about changes in position.
Beware of the Type Conversion risk and pitfalls!
Your best bet is to create a duplicate of the array, then splice from the original.
Or just go using a collection (key->value) and just delete the key eg
People = {a: "Person A", b: "Person B", c:"Person C"};
delete People.a;
delete People.c; //now the People collection only has 1 entry.
You can replace a,b,c with numbers just using it as an example,
People = {0: "Person A", 1: "Person B", 2:"Person C"};
delete People[0];
delete People[1];
this is a sample for you
<script lanauge = "javascript">
var arr = ["1","2","3","4"];
delete arr[1];// arr[1] is undefined
delete arr[2];// arr[2] is undefined
// now arr.length is 4
var todelete = [];
for (i = 0 ; i < arr.length ;i++)
{
if (typeof arr[i] == 'undefined') todelete.push(i);
}
todelete.sort(function(a, b) { return b-a }); // make the indeies from big to small
for (i = 0;i < todelete.length; i ++)
{
arr.splice(todelete[i],1);
}
// now arr.length is 2
</script>
This may not be what you want, but you can easily calculate what the final element at the end of this procedure will be, then just grab it. Assuming that the elements of the array are contiguous and start at arr[0], you can find:
var logBase2OfLength = Math.floor(Math.log(arr.length) / Math.log(2));
var finalElement = arr[(1 << logBase2OfLength) - 1];
Basically, if you take the integer power of 2 that is less than or equal to the number of elements in your array, that is the position of the element that will remain after all of the looping and deleting.
function removeUndefined(array)
{
var i = 0;
while (i < array.length)
if (typeof array[i] === 'undefined')
array.splice(i, i);
else
i++;
return array;
}
EDIT: I wrote this based on the title. Looks like the question asks something completely different.
>If you are getting undefined during deletion of the key-pair, Then to prevent "undefined" you can try code given below to delete key-pair
1) test = ["1","2","3","4",""," "];
2) var delete = JSON.stringify(test);
case1) delete = delete.replace(/\,""/g,'');
or
case2) delete = delete.replace(/\," "/g,'');
or
case3) delete = delete.replace(/\,null/g,'');
3) var result = JSON.parse(delete);
simply
[NaN, undefined, null, 0, 1, 2, 2000, Infinity].filter(Boolean)
while(yourarray.length>1) //only one left
{
// your code
}

Javascript array sort and unique

I have a JavaScript array like this:
var myData=['237','124','255','124','366','255'];
I need the array elements to be unique and sorted:
myData[0]='124';
myData[1]='237';
myData[2]='255';
myData[3]='366';
Even though the members of array look like integers, they're not integers, since I have already converted each to be string:
var myData[0]=num.toString();
//...and so on.
Is there any way to do all of these tasks in JavaScript?
This is actually very simple. It is much easier to find unique values, if the values are sorted first:
function sort_unique(arr) {
if (arr.length === 0) return arr;
arr = arr.sort(function (a, b) { return a*1 - b*1; });
var ret = [arr[0]];
for (var i = 1; i < arr.length; i++) { //Start loop at 1: arr[0] can never be a duplicate
if (arr[i-1] !== arr[i]) {
ret.push(arr[i]);
}
}
return ret;
}
console.log(sort_unique(['237','124','255','124','366','255']));
//["124", "237", "255", "366"]
You can now achieve the result in just one line of code.
Using new Set to reduce the array to unique set of values.
Apply the sort method after to order the string values.
var myData=['237','124','255','124','366','255']
var uniqueAndSorted = [...new Set(myData)].sort()
UPDATED for newer methods introduced in JavaScript since time of question.
This might be adequate in circumstances where you can't define the function in advance (like in a bookmarklet):
myData.sort().filter(function(el,i,a){return i===a.indexOf(el)})
Here's my (more modern) approach using Array.protoype.reduce():
[2, 1, 2, 3].reduce((a, x) => a.includes(x) ? a : [...a, x], []).sort()
// returns [1, 2, 3]
Edit: More performant version as pointed out in the comments:
arr.sort().filter((x, i, a) => !i || x != a[i-1])
function sort_unique(arr) {
return arr.sort().filter(function(el,i,a) {
return (i==a.indexOf(el));
});
}
How about:
array.sort().filter(function(elem, index, arr) {
return index == arr.length - 1 || arr[index + 1] != elem
})
This is similar to #loostro answer but instead of using indexOf which will reiterate the array for each element to verify that is the first found, it just checks that the next element is different than the current.
Try using an external library like underscore
var f = _.compose(_.uniq, function(array) {
return _.sortBy(array, _.identity);
});
var sortedUnique = f(array);
This relies on _.compose, _.uniq, _.sortBy, _.identity
See live example
What is it doing?
We want a function that takes an array and then returns a sorted array with the non-unique entries removed. This function needs to do two things, sorting and making the array unique.
This is a good job for composition, so we compose the unique & sort function together. _.uniq can just be applied on the array with one argument so it's just passed to _.compose
the _.sortBy function needs a sorting conditional functional. it expects a function that returns a value and the array will be sorted on that value. Since the value that we are ordering it by is the value in the array we can just pass the _.identity function.
We now have a composition of a function that (takes an array and returns a unique array) and a function that (takes an array and returns a sorted array, sorted by their values).
We simply apply the composition on the array and we have our uniquely sorted array.
This function doesn't fail for more than two duplicates values:
function unique(arr) {
var a = [];
var l = arr.length;
for(var i=0; i<l; i++) {
for(var j=i+1; j<l; j++) {
// If a[i] is found later in the array
if (arr[i] === arr[j])
j = ++i;
}
a.push(arr[i]);
}
return a;
};
Here is a simple one liner with O(N), no complicated loops necessary.
> Object.keys(['a', 'b', 'a'].reduce((l, r) => l[r] = l, {})).sort()
[ 'a', 'b' ]
Explanation
Original data set, assume its coming in from an external function
const data = ['a', 'b', 'a']
We want to group all the values onto an object as keys as the method of deduplication. So we use reduce with an object as the default value:
[].reduce(fn, {})
The next step is to create a reduce function which will put the values in the array onto the object. The end result is an object with a unique set of keys.
const reduced = data.reduce((l, r) => l[r] = l, {})
We set l[r] = l because in javascript the value of the assignment expression is returned when an assignment statement is used as an expression. l is the accumulator object and r is the key value. You can also use Object.assign(l, { [r]: (l[r] || 0) + 1 }) or something similar to get the count of each value if that was important to you.
Next we want to get the keys of that object
const keys = Object.keys(reduced)
Then simply use the built-in sort
console.log(keys.sort())
Which is the set of unique values of the original array, sorted
['a', 'b']
The solution in a more elegant way.
var myData=['237','124','255','124','366','255'];
console.log(Array.from(new Set(myData)).sort((a,b) => a - b));
I know the question is very old, but maybe someone will come in handy
A way to use a custom sort function
//func has to return 0 in the case in which they are equal
sort_unique = function(arr,func) {
func = func || function (a, b) {
return a*1 - b*1;
};
arr = arr.sort(func);
var ret = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (func(arr[i-1],arr[i]) != 0)
ret.push(arr[i]);
}
}
return ret;
}
Example: desc order for an array of objects
MyArray = sort_unique(MyArray , function(a,b){
return b.iterator_internal*1 - a.iterator_internal*1;
});
No redundant "return" array, no ECMA5 built-ins (I'm pretty sure!) and simple to read.
function removeDuplicates(target_array) {
target_array.sort();
var i = 0;
while(i < target_array.length) {
if(target_array[i] === target_array[i+1]) {
target_array.splice(i+1,1);
}
else {
i += 1;
}
}
return target_array;
}
I guess I'll post this answer for some variety. This technique for purging duplicates is something I picked up on for a project in Flash I'm currently working on about a month or so ago.
What you do is make an object and fill it with both a key and a value utilizing each array item. Since duplicate keys are discarded, duplicates are removed.
var nums = [1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10];
var newNums = purgeArray(nums);
function purgeArray(ar)
{
var obj = {};
var temp = [];
for(var i=0;i<ar.length;i++)
{
obj[ar[i]] = ar[i];
}
for (var item in obj)
{
temp.push(obj[item]);
}
return temp;
}
There's already 5 other answers, so I don't see a need to post a sorting function.
// Another way, that does not rearrange the original Array
// and spends a little less time handling duplicates.
function uniqueSort(arr, sortby){
var A1= arr.slice();
A1= typeof sortby== 'function'? A1.sort(sortby): A1.sort();
var last= A1.shift(), next, A2= [last];
while(A1.length){
next= A1.shift();
while(next=== last) next= A1.shift();
if(next!=undefined){
A2[A2.length]= next;
last= next;
}
}
return A2;
}
var myData= ['237','124','255','124','366','255','100','1000'];
uniqueSort(myData,function(a,b){return a-b})
// the ordinary sort() returns the same array as the number sort here,
// but some strings of digits do not sort so nicely numerical.
function sort() only is only good if your number has same digit, example:
var myData = ["3","11","1","2"]
will return;
var myData = ["1","11","2","3"]
and here improvement for function from mrmonkington
myData.sort().sort(function(a,b){return a - b;}).filter(function(el,i,a){if(i==a.indexOf(el) & el.length>0)return 1;return 0;})
the above function will also delete empty array and you can checkout the demo below
http://jsbin.com/ahojip/2/edit
O[N^2] solutions are bad, especially when the data is already sorted, there is no need to do two nested loops for removing duplicates. One loop and comparing to the previous element will work great.
A simple solution with O[] of sort() would suffice. My solution is:
function sortUnique(arr, compareFunction) {
let sorted = arr.sort(compareFunction);
let result = sorted.filter(compareFunction
? function(val, i, a) { return (i == 0 || compareFunction(a[i-1], val) != 0); }
: function(val, i, a) { return (i == 0 || a[i-1] !== val); }
);
return result;
}
BTW, can do something like this to have Array.sortUnique() method:
Array.prototype.sortUnique = function(compareFunction) {return sortUnique(this, compareFunction); }
Furthermore, sort() could be modified to remove second element if compare() function returns 0 (equal elements), though that code can become messy (need to revise loop boundaries in the flight). Besides, I stay away from making my own sort() functions in interpreted languages, since it will most certainly degrade the performance. So this addition is for the ECMA 2019+ consideration.
The fastest and simpleness way to do this task.
const N = Math.pow(8, 8)
let data = Array.from({length: N}, () => Math.floor(Math.random() * N))
let newData = {}
let len = data.length
// the magic
while (len--) {
newData[data[len]] = true
}
var array = [2,5,4,2,5,9,4,2,6,9,0,5,4,7,8];
var unique_array = [...new Set(array)]; // [ 2, 5, 4, 9, 6, 0, 7, 8 ]
var uniqueWithSorted = unique_array.sort();
console.log(uniqueWithSorted);
output = [ 0, 2, 4, 5, 6, 7, 8, 9 ]
Here, we used only Set for removing duplicity from the array and then used sort for sorting array in ascending order.
I'm afraid you can't combine these functions, ie. you gotta do something like this:-
myData.unique().sort();
Alternatively you can implement a kind of sortedset (as available in other languages) - which carries both the notion of sorting and removing duplicates, as you require.
Hope this helps.
References:-
Array.sort
Array.unique

Categories

Resources