I have a multidimentional array
array = [];
array[0] = [1,3,8,4,9,5];
array[1] = [5,9,4,2,9,3,0];
array[2] = [5,2,6,1,3,8,4,9,5,17,2,9,3,0];
array[3] = [-1,0,20,6];
I want to sort it to get this result
[
[-1,0,0,0,1,1],
[2,2,2,3,3,3,3],
[4,4,4,5,5,5,5,6,6,8,8,9,9,9],
[9,9,17,20]
]
I have defined this function that helped me get this result
Array.prototype.sort_multi = function()
{
var arr = [];
this.forEach(function(element_arr,index_arr,array_arr)
{
element_arr.forEach(function(element,index,array)
{
arr.push(element);
});
});
arr.sort(function (a, b) { return a - b;});
this.forEach(function(element_arr,index_arr,array_arr)
{
element_arr.forEach(function(element,index,array)
{
array_arr[index_arr][index] = arr.shift();
});
});
return this;
}
My question is: is there a simple way to do this ? for example using the function sort, or a simple algorithm ... ?
A slightly simplified (and slightly more efficient) version of sort_multi():
Basically what is happening here is:
The items in the original array are combined into one big array (for easy sorting)
We record the lengths of the original child arrays while joining
Sort the joined array numerically (as in the code you posted)
Split the sorted big array as per the lengths of the original child arrays
Return the result
Why this is more efficient than the original code:
The original code iterates through each child array element by element for joining. This is not needed since we have the natively implemented concat() for exactly that.
The original code again iterates element by element when splitting the joined/sorted array - Not needed since we have splice().
Array.prototype.sort_multi = function() {
var joined = [], lens = [], result = [];
this.forEach(function(item) {
joined = joined.concat(item);
lens.push(item.length); // store the initial lengths
});
joined = joined.sort(function (a, b) { return a - b;}); // sort numerically
lens.forEach(function(item) { // for each length in lens
result.push(joined.splice(0, item));
});
return result;
}
Related
My logic for the problem, using the below as the input.
var input = [['A','B'],1,2,3,['C','D']]
Check first element to see if is an Array or not using Array.isArray(input)
If first element is array, call function, first element ['A,'B'] as argument.
The first element of the nested array is 'A' which is not an array, so push this element into a result array, and shift this element out. Repeat the function call.
When trying to flatten nested arrays using recursion, my input variable to the function keeps getting reassigned, preventing me from calling the function again using the original array. How do I prevent the original input variable from getting reassigned?
I understand this is not the complete solution, however I am stuck at when I shift the first element out of the nested array.
I've gone through step by step with this function, but there must be something I'm missing, another set of eyes would help greatly.
I've also been using my chrome developer tool, set breakpoints to monitor the function step by step.
//Defining original input variable
var input = [['A','B'],1,2,3,['C','D']]
function flat(array){
var result = []
var firstElement = array[0]
//CHECK IF FIRST ELEMENT IS ARRAY OR NOT
if(Array.isArray(firstElement)){
return flat(firstElement)
}
//IF ELEMENT NOT ARRAY, PUSH ELEMENT TO RESULT
else{result.push(firstElement)
array.shift() //removing child element
return (flat(array)) //call function on same array
}
if(array.length===0){return result}
}
First iteration:
firstElement = ['A','B'], Array.isArray(firstElement) would be true, hence call flat(firstElement)
Second Iteration:
firstElement = 'A', Array.isArray(firstElement) is false, so we
1. jump down to push this element into result
2. remove 'A' by using array.shift()
3. Call flat(array), where array is now ['B']
Third Iteration:
firstElement = 'B', Array.isArray(firstElement) is false
1. jump down to push this element into result, result is now only ['B'] since I've reset the result when I recalled the function.
2. remove 'B' by using array.shift(), array is now empty, ->[ ]
3. How can I step out, and use flat() on the original input array?
Your code doesn't consider the following elements if the first element is an array. The solution below uses array.concat(...) to combine both the result of the recursion (going down the tree), but also to combine the results of processing the rest of the list (in the same level). Visualizing the problem as a tree, often helps with recursions IMO:
[] 1 2 3 []
| |
A [] C D
|
B C
So perhaps it is more clear here, that we must both concat the result of the recursion and the result of taking a "step" to the right (recursion again) which would otherwise be a loop iterating the array.
var input = [['A',['B', 'C']],1,2,3,['C','D']]
function flat(array) {
var result = []
if (array.length == 0) return result;
if (Array.isArray(array[0])) {
result = result.concat(flat(array[0])); // Step down
} else {
result.push(array[0]);
}
result = result.concat(flat(array.slice(1))) // Step right
return result;
}
console.log(flat(input));
// ["A", "B", "C", 1, 2, 3, "C", "D"]
This is somewhat analogous to a version with loops:
function flat(array) {
var result = []
for (var i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
result = result.concat(flat(array[i]));
} else {
result.push(array[i]);
}
}
return result;
}
EDIT: For debugging purposes, you can track the depth to help get an overview of what happens where:
var input = [['A',['B', 'C']],1,2,3,['C','D']]
function flat(array, depth) {
var result = []
if (array.length == 0) return result;
if (Array.isArray(array[0])) {
result = result.concat(flat(array[0], depth + 1));
} else {
result.push(array[0]);
}
var res1 = flat(array.slice(1), depth);
console.log("Depth: " + depth + " | Concatenating: [" + result + "] with: [" + res1 + "]");
result = result.concat(res1)
return result;
}
console.log(flat(input, 0));
If you want to avoid loops, and I'm considering concating/spreading arrays as loops, you need to pass the result array to your function.
const input = [['A', 'B'], 1, 2, 3, ['C', 'D']]
// Start the function with an empty result array.
function flat(array, result = []) {
if (!array.length)
return result
// Extract first element.
const first = array.shift()
// Call the function with the array element and result array.
if (Array.isArray(first))
flat(first, result)
// Or add the non array element.
else
result.push(first)
// Call the function with the rest of the array and result array.
flat(array, result)
return result
}
console.log(flat(input))
Here is my answer if you are using JavaScript
You can use the below one line code to flatten n level nested Array
let flattendArray = input.flat(Infinity);
Or use this approach using reduce and concat
function flatDeep(arr, d = 1) {
return d > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val), [])
: arr.slice();
};
Refer this link
I am using a kind of dict in javascript and want to add an element to a list which is part of a kind of dictionary.
Here is the code snippet:
lines = [
[1,2],
[2,4],
[2,3],
[3,5]
];
nodes = [1,2,3,5,4];
function get_adjdict(nodes, lines) {
// create an empty something
adjacent = [];
// loop over all elements on the array 'nodes'. The variable 'node' is supposed to take the various values of the elements in 'nodes'. So in this example this will be the values 1,2,3,5,4.
for (var node in nodes) {
// Add a key-value pair to the object/array/whatever named 'adjacent'. key is the value of 'node, the value is an empty array.
adjacent.push({node:[]});
// loop over all elements on the array 'lines'. The variable 'line' is supposed to take the various values of the elements in 'lines'. So in this example this will be the values [1,2], then [2,4] and so on
for (var line in lines) {
// checks if the value of 'node' is present in the array 'line'
if (line.includes(node)) {
// If the first element of the array 'line' has the same value as 'node'...
if (line[0] == node) {
// ... add the second element of 'line' to 'adjacent[node]'
adjacent[node].push(line[1]) //ERROR
} else {
// ... add the first element of 'line' to 'adjacent[node]'
adjacent[node].push(line[0])
}
}
}
}
return adjacent
}
The error is "TypeError: adjacent[node].push is not a function". How to do it then?
Expected data-structure:
adjdict = {
1: [2],
2: [1,4,3],
3: [2,5],
4: [2],
5: [3]
}
This what you are looking for:
var lines = [
[1,2],
[2,4],
[2,3],
[3,5]
];
var nodes = [1,2,3,4,5];
function get_adjdict (nodes, lines) {
var adjacent = {};
var node, line;
for (var node_idx in nodes) {
node = nodes[node_idx];
adjacent[node] = [];
for (var line_idx in lines) {
line = lines[line_idx];
if (line.includes(node)) {
if (line[0] == node) {
adjacent[node].push(line[1]);
} else {
adjacent[node].push(line[0]);
}
}
}
}
return adjacent;
}
get_adjdict(nodes, lines);
Bear in mind that, when using the construction for (var idx in arr) {} in JavaScript, idx is the key in the iteration, not the value.
for (var node in nodes) {
In the above code, node takes values 0 to 4. nodes[node] would take values 1 to 5 as I think you are expecting.
I always use the suffix _idx for this kind of variables. In this case, rename node to node_idx or node_index and you will see how everything falls into place.
You could just iterate the lines and create the object.
function add(o, k, v) {
if (!o[k]) {
o[k] = [];
}
if (o[k].indexOf(v) === -1) {
o[k].push(v);
}
}
var lines = [[1, 2], [2, 4], [2, 3], [3, 5]],
result = {};
lines.forEach(function (l) {
add(result, l[0], l[1]);
add(result, l[1], l[0]);
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can simplify it with first mapping all of the indexes first and than use a simple reduce to build the object.
const lines = [
[1,2],
[2,4],
[2,3],
[3,5]
];
const nodes = [1,2,3,4,5];
// Make a lookup table where all the numbers appear
var lookup = lines.slice(0).reduce( (o, node, i) => {
o[node[0]] = o[node[0]] || []; // if we have not found it, set an array
o[node[0]].push(node[1]); // add index value to the array
o[node[1]] = o[node[1]] || []; // if we have not found it, set an array
o[node[1]].push(node[0]); // add index value to the array
return o //return object for reduce
}, {})
var result = nodes.reduce( (o, n) => { //now loop over the nodes and make the `hash` table
o[n] = lookup[n] || []
return o
}, {})
console.log(result)
Don't use for/in loops on arrays. They can wind up iterating inherited properties as well as array items. for/in is for object iteration. Use .forEach() instead which will make working with the enumerated items much simpler (no indexes to manage).
Next, you are indicating that you want an object outputted, but you are creating adjacent as an array. Arrays inherit from objects, but they store their data differently.
Also, remember to formally declare your variables, otherwise they become global.
Lastly, don't rely on automatic semi-colon insertion. That can lead to bugs in certain edge cases.
If you follow good coding best practices, a lot of these kinds of issues just go away.
// Don't forget to use "var" to declare your variables otherwise
// they will become global.
var nodes = [1,2,3,4,5];
var lines = [
[1,2],
[2,4],
[2,3],
[3,5]
];
function get_adjdict(nodes, lines) {
var adjacent = {}; // <-- You are asking for an object, not an array
// Loop through the nodes array (use .forEach() to loop arrays)
nodes.forEach(function(node){
// Array to store results in
var results = [];
// Loop through the lines
lines.forEach(function(line) {
if (line.includes(node)) {
if (line[0] === node) {
results.push(line[1]);
} else {
results.push(line[0]);
}
// Set array as new property value
adjacent[node] = results;
}
});
});
// This needs to be outside of all loops, just before function terminates
return adjacent;
}
console.log(get_adjdict(nodes, lines));
I'm trying to learn JavaScript well and am practicing rebuilding some underscore functions. I'm trying to rebuild zip using map where there is an arbitrary number of arguments. Here is the solution I came up with, with pluck. I know that the underscore implementation itself uses _pluck, which internally uses Map, so I wanted to see if it was possible to do this with map...
_.zip = function() {
var argumentsArray = Array.prototype.slice.call(arguments);
var longestArray = argumentsArray.sort(function(a, b) {
return b.length - a.length
})[0];
//create and return an array that is as long as the longestArray:
var zipped = Array(longestArray.length);
// you want to push each element from each array onto an array with the length of the longestArray.
for (var i = 0; i < longestArray.length; i++) {
zipped[i] = _.pluck(argumentsArray, i)
};
return zipped;
}
I'm stuck on what to return inside the map function below. I know I have to do some sort of a loop up to the length of the longest element, since the returned array should be that long. How would I do that inside map? Or, should I just do two for loops instead of trying to use map?
zip = function() {
//get the longest input argument:
var argumentsArray = Array.prototype.slice.call(arguments);
var longestArray = argumentsArray.sort(function(a, b) {
return b.length - a.length
})[0];
//trying to use map here:
return map(argumentsArray, function(val){
return ?
})
};
console.log(zip([1, 2, 4], [1]))
// returns [[1, 1],[2, undefined],[4, undefined]]
Below I have attached what should be a working copy of your original implementation without the use of pluck using only maps.
var zip = function() {
var argumentsArray = Array.prototype.slice.call(arguments);
var longestArray = argumentsArray.sort(function(a, b) {
return b.length - a.length
})[0];
return longestArray.map(function(value, index, array) {
return argumentsArray.map(function(val, i, arr) {
return val[index];
});
});
};
The outer map over longestArray acts solely as a looping mechanism so it would be better suited to use a for-loop instead.
The inner loop maps over the array of arguments passed in and, using the current index of the outer map, returns the ith element of each argument array. Since map already returns a new array, each iteration of the inner map will return an array containing the ith elements for each argument array.
Below is another implementation using a for loop and a map.
function zip() {
//turn args into an array
var argumentsArray = Array.prototype.slice.call(arguments);
var returnArr = [];
//get length of longest array
var length = argumentsArray.reduce(function (prev, curr) {
//starter val is 0, if curr array is longer replace with its length
return (prev >= curr.length) ? prev : curr.length;
}, 0);
//push an array of the ith element of each of the argument arrays
//into the return array
for (var i = 0; i < length; i++) {
returnArr.push(argumentsArray.map(function (val) {
return val[i];
}));
}
return returnArr;
}
Also note that instead of sorting to find the largest array, I reduce over the array lengths to find and return the longest length.
Since js sort is in-place it will potentially change your arguments array order. Your returned array of zipped elements will then be ordered by their original array lengths. Doing it this way they will instead be in the order that the argument arrays were passed in. But both are valid zip implementations depending on what you need.
Hope this helps!
I was trying to create a 3-dimensional array and couldn't find an easy way to do it.
array = [[[]]];
or
array = [][][];
or
array = []; array[] = []; array[][] = [];
would for example not work. (the console'd say the second array is 'undefined' and not an object, or for the second and third example give a parse error).
I cannot hard-code the information either, as I have no idea what the indexes and contents of the array are going to be (they are created 'on the fly' and depending on the input of a user. eg the first array might have the index 4192). I may have to create every array before assigning them, but it would be so much easier and faster if there's an easier way to define 3-dimensional arrays. (there'll be about 2 arrays, 25 subarrays and 800 subsubarrays total) every millisecond saves a life, so to say.
help please?
JavaScript is dynamically typed. Just store arrays in an array.
function loadRow() {
return [1, 2, 3];
}
var array = [];
array.push(loadRow());
array.push(loadRow());
console.log(array[1][2]); // prints 3
Since arrays in javascript aren't true arrays, there isn't really a multidimensional array. In javascript, you just have an arrays within an array. You can define the array statically like this:
var a = [
[1,2,3],
[4,5,6],
[7,8,9]
];
Or dynamically like this:
var d = [];
var d_length = 10;
for (var i = 0;i<d_length;i++) {
d[i] = [];
}
UPDATE
You could also use some helper functions:
function ensureDimensions(arr,i,j,k) {
if(!arr[i]) {
arr[i] = [];
}
if(!arr[i][j]) {
arr[i][j] = [];
}
}
function getValue(arr,i,j,k) {
ensureDimensions(i,j,k);
return arr[i][j][k];
}
function setValue(arr,newVal,i,j,k) {
ensureDimensions(i,j,k);
arr[i][j][k] = newVal;
}
I have an array of objects in javascript. I use jquery.
How do i get the first element in the array? I cant use the array index - as I assign each elements index when I am adding the objects to the array. So the indexes arent 0, 1, 2 etc.
Just need to get the first element of the array?
If you don't use sequentially numbered elements, you'll have to loop through until you hit the first one:
var firstIndex = 0;
while (firstIndex < myarray.length && myarray[firstIndex] === undefined) {
firstIndex++;
}
if (firstIndex < myarray.length) {
var firstElement = myarray[firstIndex];
} else {
// no elements.
}
or some equivalently silly construction. This gets you the first item's index, which you might or might not care about it.
If this is something you need to do often, you should keep a lookaside reference to the current first valid index, so this becomes an O(1) operation instead of O(n) every time. If you're frequently needing to iterate through a truly sparse array, consider another data structure, like keeping an object alongside it that back-maps ordinal results to indexes, or something that fits your data.
The filter method works with sparse arrays.
var first = array.filter(x => true)[0];
Have you considered:
function getFirstIndex(array){
var result;
if(array instanceof Array){
for(var i in array){
result = i;
break;
}
} else {
return null;
}
return result;
}
?
And as a way to get the last element in the array:
function getLastIndex(array){
var result;
if(array instanceof Array){
result = array.push("");
array.pop;
}
} else {
return null;
}
return result;
}
Neither of these uses jquery.
Object.keys(array)[0] returns the index (in String form) of the first element in the sparse array.
var array = [];
array[2] = true;
array[5] = undefined;
var keys = Object.keys(array); // => ["2", "5"]
var first = Number(keys[0]); // => 2
var last = Number(keys[keys.length - 1]); // => 5
I was also facing a similar problem and was surprised that no one has considered the following:
var testArray = [];
testArray [1245]= 31;
testArray[2045] = 45;
for(index in testArray){
console.log(index+','+testArray[index])
}
The above will produce
1245,31
2045,45
If needed you could exist after the first iteration if all that was required but generally we need to know where in the array to begin.
This is a proposal with ES5 method with Array#some.
The code gets the first nonsparse element and the index. The iteration stops immediately with returning true in the callback:
var a = [, , 22, 33],
value,
index;
a.some(function (v, i) {
value = v;
index = i;
return true;
});
console.log(index, value);
If you find yourself needing to do manipulation of arrays a lot, you might be interested in the Underscore library. It provides utility methods for manipulating arrays, for example compact:
var yourArray = [];
yourArray[10] = "foo";
var firstValue = _.compact(yourArray)[0];
However, it does sound like you are doing something strange when you are constructing your array. Perhaps Array.push would help you out?