Clone Multidimensional Array in javascript - javascript

I want to make a clone of multidimensional Array so that i can play arround with the clone array without affecting main Array.
I'm using following function to do so:
Array.prototype.clone = function () {
var newArray = new Array(this.length);
for(var i=0; i < this.length; i++ ){
newArray[i] = this[i];
}
return newArray;
};
But problem which is since it is using array prototype so it will clone my all array.so can any body tell me what is the best way of doing this.

vsync is correct, my first answer doesn't handle var a = [[1,2],[3,4]];
So here's an improved version
var a = [[1,2],[3,4]];
Array.prototype.clone = function() {
var arr = this.slice(0);
for( var i = 0; i < this.length; i++ ) {
if( this[i].clone ) {
//recursion
arr[i] = this[i].clone();
}
}
return arr;
}
var b = a.clone()
console.log(a);
console.log(b);
b[1][0] = 'a';
console.log(a);
console.log(b);
//[[1, 2], [3, 4]]
//[[1, 2], [3, 4]]
//[[1, 2], [3, 4]]
//[[1, 2], ["a", 4]]

You need to use recursion
var a = [1,2,[3,4,[5,6]]];
Array.prototype.clone = function() {
var arr = [];
for( var i = 0; i < this.length; i++ ) {
// if( this[i].constructor == this.constructor ) {
if( this[i].clone ) {
//recursion
arr[i] = this[i].clone();
break;
}
arr[i] = this[i];
}
return arr;
}
var b = a.clone()
console.log(a);
console.log(b);
b[2][0] = 'a';
console.log(a);
console.log(b);
/*
[1, 2, [3, 4, [5, 6]]]
[1, 2, [3, 4, [5, 6]]]
[1, 2, [3, 4, [5, 6]]]
[1, 2, ["a", 4, [5, 6]]]
*/
Any other objects in the original array will be copied by reference though

I found that this approach is better than meouw's :
var source = [
[1, 2, {c:1}],
[3, 4, [5, 'a']]
];
// Create a new method ontop of the "Array" primitive prototype:
Array.prototype.clone = function() {
function isArr(elm) {
return String(elm.constructor).match(/array/i) ? true : false;
}
function cloner(arr) {
var arr2 = arr.slice(0),
len = arr2.length;
for (var i = 0; i < len; i++)
if (isArr(arr2[i]))
arr2[i] = cloner(arr2[i]);
return arr2;
}
return cloner(this);
}
// Clone
var copy = source.clone();
// modify copy
copy[0][0] = 999;
console.dir(source);
console.dir('**************');
console.dir(copy);
Another method, which can only work on data sets which have primitives as values (String, Numbers, Objects) :
var source = [
[1,2, {a:1}],
["a", "b", ["c", 1]]
];
// clone "srouce" Array
var copy = JSON.parse(JSON.stringify(source));
// modyfy clone
copy[0][0] = 999;
// print both arrays
console.dir(copy)
console.log('***********')
console.dir(source)

Related

Check array overlapping in JavaScript

I have some arrays like [1,5], [3,6], [2,8],[19,13], [12,15]. When i pass two arrays in the function output will be [1,6], [2,19],[12,15]
i want to remove overlapping numbers from 2 arrays . like on fist and second array 5 and 3 will be overlap between 1 to 6.
I believe this is what you want (you get the min of the first array and the max of the second array):
function removeOverlap(arr1, arr2) {
if (arr1 === undefined) {
return arr2;
}
if (arr2 === undefined) {
return arr1;
}
return [Math.min.apply(null, arr1), Math.max.apply(null, arr2)];
}
// Sample:
var myArrays = [[1,5], [3,6], [2,8], [19,13], [12,15]];
for (var i = 0; i < myArrays.length; i = i + 2) {
console.log(removeOverlap(myArrays[i], myArrays[i + 1]));
}
EDIT: answer with multiple parameters as you requested in your comment:
We could use rest parameters in the answer below, but I will use the arguments object for compatibility with Internet Explorer. If this is not a requirement you can adapt the solution to use the first.
function removeOverlap(arr1, arr2) {
// Converting the arguments object to array:
var argsArray = Array.prototype.slice.call(arguments);
// Removing undefined:
argsArray = argsArray.filter(function(el) {
return el != undefined;
});
// Alternative (not compatible with Internet Explorer):
//argsArray = argsArray.filter(el => el);
// We're looking for the min and max numbers, let's merge the arrays
// e.g. transform [[1, 5], [3, 6], [2, 8]] into [1, 5, 3, 6, 2, 8]
var merged = [].concat.apply([], argsArray);
// Alternative, but it is not compatible with Internet Explorer:
//var merged = Array.flat(argsArray);
return [Math.min.apply(null, merged), Math.max.apply(null, merged)];
}
// Sample:
var myArrays = [[1,5], [3,6], [2,8], [19,13], [12,15]];
for (var i = 0; i < myArrays.length; i = i + 2) {
console.log(removeOverlap(myArrays[i], myArrays[i + 1]));
}
console.log(removeOverlap(myArrays[0], myArrays[1], myArrays[2]));
This can easily be accomplished my finding the min of the current and max of the next item.
let initial = [ [1, 5], [3, 6], [2, 8], [19, 13], [12, 15] ]
let expected = [ [1, 6], [2, 19], [12, 15] ]
let actual = calculateOverlaps(initial);
console.log(JSON.stringify(actual) === JSON.stringify(expected)); // true
function calculateOverlaps(arr) {
let result = [];
for (let i = 0; i < arr.length; i+=2) {
if (i >= arr.length - 1) {
result.push(arr[i]); // If the array has an odd size, get last item
} else {
let curr = arr[i];
let next = arr[i + 1];
result.push([ Math.min(...curr), Math.max(...next) ]);
}
}
return result;
}
Here is a more code-golf oriented function:
const calculateOverlaps1 = (arr) => arr.reduce((r, e, i, a) =>
(i % 2 === 0)
? r.concat([
(i < a.length - 1)
? [ Math.min(...e), Math.max(...a[i+1]) ]
: e
])
: r, []);
And even smaller, at just 101 bytes.
f=a=>a.reduce((r,e,i)=>i%2===0?r.concat([i<a.length-1?[Math.min(...e),Math.max(...a[i+1])]:e]):r,[]);

Find Matches in Array

I have array1 = [4, 5, 6, 7, 4, 5]; and array2 = [4, 5].
And I want to match array2 in array1 and to output the number of times it matched.
var array1 = [4, 5, 6, 7, 4, 5];
var array2 = [4, 5];
function match(a1, a2) {
//matches 4,5 twice bc it is in array1
}
match(array1, array2) //output: 2;
You have to use a nested loop and compare each index of both arrays with each other.
var count = 0;
for (var i = 0; i < a1.length; i++)
{
for (var j = 0; j < a2.length; j++)
{
if (a1[i]==a2[j])
{
count +=1;
}
}
}
The best way to solve your problem is by intersection.
The solution for your problem: https://stackoverflow.com/a/1885660/4120554
What you're asking for is called an intersection. If you're only interested in the number of matches, this function should do the trick:
var array1 = [4, 5, 6, 7, 4, 5];
var array2 = [4, 5];
function intersectCount(arr1, arr2) {
var c = 0;
for(const item of arr2) {
if (arr1.indexOf(item) != -1) c++;
}
return c;
}
intersectCount(array1, array2); // result: 2
You can use below code for your question;
var array1 = [4, 5, 6, 7, 4, 5];
var array2 = [4, 5];
function match(a1, a2) {
var result = [];
for(const item of a2) {
if (a1.indexOf(item) > -1 ) {
result.push (item);
}
}
return result.length;
}
If you want to compare each index:
var match = (arr1,arr2)=>arr1.filter((el,i)=>el === arr2[i]).length;
If you want to count all elements that exist in both arrays, may unify one through a set:
function match(arr1,arr2){
var set = new Set( arr2 );
return arr1.filter( el => set.has(el) ).length;
}

Replace array elements without losing reference?

How does one replace all elements of an array without losing references?
var arr = [1, 2, 3];
var b = arr;
b == arr; // true
magic(arr, [4, 5, 6]);
b == arr; // should return true
One way of doing it is by popping and pushing. Is there a clean way?
You could splice the old values and append the new values.
function magic(reference, array) {
[].splice.apply(reference, [0, reference.length].concat(array));
}
var arr = [1, 2, 3],
b = arr;
console.log(b === arr); // true
magic(arr, [4, 5, 6]);
console.log(b === arr); // should return true
console.log(arr);
Another way, is to use Object.assign. This requires to set the length of the array, if it is smaller than the original array.
function magic(reference, array) {
Object.assign(reference, array, { length: array.length });
}
var arr = [1, 2, 3],
b = arr;
console.log(b === arr); // true
magic(arr, [4, 5, 6, 7]);
console.log(b === arr); // should return true
console.log(arr);
The magic part could be:
arr.splice(0, arr.length, 4, 5, 6);
var arr = [1, 2, 3];
var b = arr;
b == arr; // true
arr.splice(0, arr.length, 4, 5, 6);
console.log(b);
console.log(arr);
console.log(arr === b);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you already have the replacing array in a variable (let's say repl = [4, 5, 6]), then use the rest parameters syntax:
arr.splice(0, arr.length, ...repl);
var arr = [1, 2, 3];
var b = arr;
var repl = [4, 5, 6];
b == arr; // true
arr.splice(0, arr.length, ...repl);
console.log(b);
console.log(arr);
console.log(arr === b);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's one way:
var arr = [1, 2, 3];
var b = arr;
console.log(`b == arr, b
`, b == arr, b.join());
var c = magic(arr, [4, 5, 6]);
console.log(`b == arr, b
`, b == arr, b.join());
console.log(`c == arr, c
`, c == arr, c.join());
function magic(to, from) {
// remove elements from existing array
var old = to.splice(0);
for (var i = 0; i < from.length; i++) {
to[i] = from[i];
}
return old;
}
This implementation returns a copy of the old elements that were originally in the array.
Copy the new values over the old ones.
function magic(arr, newvals) {
for (let i = 0; i < newvals.length; i++) arr[i] = newvals[i];
arr.length = newvals.length;
}
function replaceArrValues(arrRef, newValues)
{
arrRef.length = 0; // clear the array without losing reference
newValues.forEach(x => arrRef.push(x));
}

Java Script - Adding null value to array, if the element is not present at particular index

Array length is 7
Original array
var arr = [2, 4, 6];
Needed array
arr = [null,null,2,null,4,null,6];
0 is not present in array so need to replace with null,
1 is not available replace with null and
2 is available so put 2 in new array so on..
You can use the splice() method on the array
var arr=[2,4,6];
var l = arr[arr.length-1];
for(var i=0; i<=l; i++){
if(arr[i] !== i){
arr.splice(i, 0, null);
}
}
Output : [null, null, 2, null, 4, null, 6]
This modifies the original array.
I will write a permanence case for all answers soon.
function createArrayFromArray(array, length) {
var new_array = new Array(length);
for (var i = 0; i < new_array.length; i++) {
new_array[i] = null;
}
for (var i = 0; i < array.length; i++) {
new_array[array[i]] = array[i];
}
return new_array;
}
console.log(createArrayFromArray(arr, 7)); //[null, null, 2, null, 4, null, 6]
You just need to find the max value in the array and then iterate from 0 to that max, checking each value to see if it was present in the source or not:
var arr = [2, 4, 6];
var max = Math.max.apply(Math, arr);
var result = [];
for (var i = 0; i <= max; i++) {
if (arr.indexOf(i) !== -1) {
result[i] = i;
} else {
result[i] = null;
}
}
Working demo: http://jsfiddle.net/jfriend00/c7p8mkqy/
As I asked in my comments, I'd like to know what problem you're actually trying to solve because it seems like both the original and the newly created data structures are inefficient structures that could probably use different form of data and work more efficiently. But, we can only help you make a wiser choice if you explain the actual problem, rather just your attempted solution.
Given you have the only input arr which you want to fill null inside. Try this:
var arr = [2, 4, 6];
var output = [];
while (arr.length>0){
var first = arr.splice(0,1);
while (output.length<first[0])
output.push(null);
output.push(first[0]);
}
// output should be [null,null,2,null,4,null,6];
Try:
var arr = [2, 4, 6];
var new_arr = [];
var i = 0;
while(i < 7){
var pos = arr.indexOf(i++);
new_arr.push(pos !== -1 ? arr[pos] : null)
}
document.write(JSON.stringify(new_arr, null, 4))
var arr = [2, 4, 6];
var result = new Array(7);
arr.forEach(function(a) { result[a] = a;});
Interesting quiz:
var arr = [2, 4, 6]
var n = 0
while(arr.length > n) {
if(arr[n] !== n) {
arr = arr.slice(0,n).concat(null, arr.slice(n))
}
n++
}
console.log(arr) // [null, null, 2, null, 4, null, 6]
This approach applies to array consists of random number of sorted integers.
var arr = [2, 4, 6];
var narr = (new Array(arr.sort()[arr.length-1]))
arr.map(function(v){
narr[v] = v;
});
for (var i = 0; i<narr.length; i++) narr[i]||(narr[i]=null);
console.log(narr);
Try splice():
var arr = [2, 4, 6];
var i = 0,
l = arr[arr.length - 1];
while (i < l) {
if(i !== arr[i])
arr.splice(i, 0, null);
i++;
}
console.log(arr); //[ null, null, 2, null, 4, null, 6 ]

Calculate Average value for multidimensional array

I have an example array. It contains a day and a number of failures of builds.
var array = [["2014-08-13",3],
["2014-08-13",3],
["2014-08-14",4],
["2014-08-12",2],
["2014-08-13",3],
["2014-08-12",2]];
I want to iterate through the array and get an array which holds for each day the average value of number of failures. I tried out some things but couldn't find a proper solution.
The target array should look like this:
var targetArray = [["2014-08-13",3],
["2014-08-14",4],
["2014-08-12",2]];
what I got so far is to make an array which holds the three dates:
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] == obj) {
return true;
}
}
return false;
}
var array = [
["2014-08-13", 3],
["2014-08-13", 3],
["2014-08-14", 4],
["2014-08-12", 2],
["2014-08-13", 3],
["2014-08-12", 2]];
var targetArray = [];
for (var i = 0; i < array.length; i++) {
var temporaryArr = [];
var current = array[i];
var currentDate = current[0];
var currentValue = current[1];
console.log("current: " + current);
if (!targetArray.contains(currentDate)) {
temporaryArr[0] = currentDate;
targetArray[targetArray.length] = temporaryArr;
}
}
console.log(targetArray);
First, your dates need to be strings or you'll start getting some really weird output:
var arr = [
['2014-08-13', 3],
['2014-08-13', 3],
['2014-08-14', 4],
['2014-08-12', 2],
['2014-08-13', 3],
['2014-08-12', 2]
];
Create a new object. We're going to use its keys to store our dates and values to store the failures and number of times that day has appeared.
var obj = {};
Loop over the array. If the key/date doesn't exist add it to the object and set the value to an array containing the number of failures and set the current count to 1. If the key/date does exist, add the number of fails to the fail total and increment the count.
for (var i = 0, l = arr.length; i < l; i++) {
var el = arr[i];
var date = el[0];
var fails = el[1];
if (!obj[date]) {
obj[date] = [fails, 1]
} else {
obj[date] = [obj[date][0] + fails, obj[date][1] + 1]
}
}
Finally loop over the object and push the date and average back to a new array.
var out = [];
for (var date in obj) {
out.push([date, obj[date][0] / obj[date][1]])
}
DEMO
Code below:
var array = [
["2014-08-13", 3],
["2014-08-14", 4],
["2014-08-13", 3],
["2014-08-12", 2],
["2014-08-13", 3],
["2014-08-12", 2]
];
function average(array) {
var ret = {}, retArr = [], tmp, time, value;
for(var i=0, len=array.length; i < len; i++) {
tmp = array[i];
time = tmp[0];
value = tmp[1];
if(time in ret) {
ret[time].push(value)
} else {
ret[time] = [value];
}
}
for(var p in ret) {
var total = 0;
ret[p].forEach(function(val) {
total += val;
});
retArr.push([p, total / ret[p].length]);
}
return retArr;
}
average(array);
var myArray = [["2014-08-13", 3],
["2014-08-13", 3],
["2014-08-14", 4],
["2014-08-12", 2],
["2014-08-13", 3],
["2014-08-12", 2]];
function getAverage(arr) {
var dates = [];
var values = [];
for(i=0; i<arr.length; i++){
var index = dates.indexOf(arr[i][0]);
if(index == -1){
dates.push(arr[i][0]);
values.push([arr[i][1]]);
}else{
values[index].push(arr[i][1]);
}
}
for(d=0; d<dates.length;d++){
var dateTotal = 0;
for(a=0;a<values[d].length;a++){ dateTotal += values[d][a] }
dates[d] = [dates[d], (dateTotal / values[d].length)]
}
return dates
};
getAverage(myArray);

Categories