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));
}
Related
I have two arrays:
var array1= [1,3,5,7,9,11]
var array2= [undefined,4,6]
I need to merge one element of the array1, then one element of the array2, etc. This is my code:
function mergeArrays(array1, array2){
var array3 = [];
maxlength = Math.max(array1.length, array2.length);
for(i=0;i<maxlength;i++){
array3.push(array1[i]);
array3.push(array2[i]);
}
return console.log(array3);
}
The output now is:
array3 = [1,undefined,3,4,6,7,undefined,9,undefined,11,undefined]
I need the output to be:
array3 = [1,undefined,3,4,6,7,8,11]
I mean, I can't use ( != undefined), because if I have an undefined in the middle of the array it has to be there.
You are not placing a check for the length of shorter array.
Your function is fetching a value which is higher than the length of the array, hence, extra undefined. This should do the job
var array1 = [1, 3, 5, 7, 9, 11];
var array2 = [undefined, 4, 6];
function mergeArrays(array1, array2) {
var array3 = [];
maxlength = Math.max(array1.length, array2.length);
for (i = 0; i < maxlength; i++) {
if (i < array1.length) array3.push(array1[i]);
if (i < array2.length) array3.push(array2[i]);
}
return console.log(array3);
}
mergeArrays(array1, array2);
You can grab the max length of the two arrays and loop until you hit that value. While looping, check if the length has been exceeded and push onto the result.
const allEqual = (...args) =>
((head, ...tail) => tail.every(curr => curr === head))
(args.map(v => JSON.stringify(v)));
const test = ({ actual, expected }) => {
console.log(JSON.stringify(actual));
console.log(allEqual(actual, expected));
};
const interlaceArrays = (...arrays) => {
const result = [];
const maxLen = Math.max(...arrays.map(({ length }) => length));
for (let i = 0; i < maxLen; i++) {
arrays.forEach(arr => {
if (i < arr.length) result.push(arr[i]);
})
}
return result;
};
const
odd = [1, 3, 5, 7, 9, 11],
even = [undefined, 4, 6],
other = ['a', 'b'];
test({
actual: interlaceArrays(odd, even),
expected: [1, undefined, 3, 4, 5, 6, 7, 9, 11]
});
test({
actual: interlaceArrays(odd, even, other),
expected: [1, undefined, 'a', 3, 4, 'b', 5, 6, 7, 9, 11]
});
.as-console-wrapper { top: 0; max-height: 100% !important; }
function removeListedValues(arr) {
var what, a = arguments, L = a.length, ax;
while (L > 1 && arr.length) {
what = a[--L];
while ((ax= arr.indexOf(what)) !== -1) {
arr.splice(ax, 1);
}
}
return arr;
}
arr: The given array
without: A list of elements which are to be removed from arr.
Return the array after removing the listed values.
Input:
arr: [1, 2, 2, 3, 1, 2]
without: [2, 3]
Output:
[1, 1]
To remove something in array, suggest using .filter
const input = [1, 2, 2, 3, 1, 2];
const without = [2, 3];
const result = input.filter(value => !without.includes(value))
console.log(result)
You can create a Set (for faster lookup) from the array of values to exclude and use Array#filter along with Set#has.
const arr = [1, 2, 2, 3, 1, 2], without = new Set([2, 3]);
const res = arr.filter(x => !without.has(x));
console.log(res);
I am trying to compare 2 arrays and return a new array with any items only found in one of the two given arrays.
So here is what I got:
function diffArray(arr1, arr2) {
var newArr = [];
var max;
var test;
(arr1.length > arr2.length) ? (max = arr1, test = arr2) : (max = arr2, test = arr1);
for (let i = 0; i < test.length; i++) {
if (max.indexOf(test[i]) === -1) {
newArr.push(test[i])
}
}
return newArr;
}
console.log(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]));
However, when I run it, newArr returns an empty array. Can someone point out the error?
The error is that you are only checking the values in one array. You have to check for if values in arr1 are in arr2 and if values of arr2 are in arr1.
note: I added extra values to the arrays for testing
function diffArray(arr1, arr2) {
var newArr = [];
arr1.forEach(element => {
if(arr2.indexOf(element) === -1){
newArr.push(element)
}
});
arr2.forEach(element => {
if(arr1.indexOf(element) === -1){
newArr.push(element)
}
});
return newArr
}
console.log(diffArray([1, 2, 3,6, 5,7], [1, 2, 3, 4,10,23,11,123, 5]));
console.log(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]));
function diffArray(arr1, arr2) {
var newArr = [];
let checkArr = [];
for (const val of arr1) {
checkArr[val] = 0
}
for (const val of arr2) {
checkArr[val] = checkArr[val] !== undefined ? checkArr[val] + 1 : 0
}
for (const val of arr1) {
if (checkArr[val] === 0) {
newArr.push(val)
}
}
for (const val of arr2) {
if (checkArr[val] === 0) {
newArr.push(val)
}
}
return newArr;
}
console.log(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]));
I am trying to remove duplicates from my 2D array but no success.
Here is what I am doing any idea where am making mistake?
function Remove_duplicates_from_2d_array(data_array) {
if (data_array.length > 0) {
let unique_index_counter = 0;
// loop on target array
for (var a = 0; a < data_array.length; a++) {
var unique_array = data_array[unique_index_counter];
if (a === unique_index_counter) {
continue;
}
console.log('comparing index: ' + a + ' ( ' + data_array[a] + ' ) -- index: ' + a + ' ( ' + data_array[a] + ' )');
if (data_array[a].sort().join(',') === unique_array.sort().join(',')) {
console.log('match it index ' + a + ' - ' + unique_index_counter);
// same arrays
data_array.splice(a, 1);
a = 0; // reset for loop as splice will rebuilt array
}
// a will be equal to data_array length incase there is no match found
if (a === data_array.length) {
unique_index_counter++;
}
if(unique_index_counter != data_array.length) {
a = 0; // reset for loop because we have not checked all items
}
}
return data_array;
} else {
return [];
}
}
var a1 = [1, 2, 3];
b1 = [4, 4, 5];
c1 = [3, 4, 5];
d1 = [4, 4, 5];
var data_array = [];
data_array.push(a1);
data_array.push(b1);
data_array.push(c1);
data_array.push(d1);
console.log('original array.');
console.log(data_array);
var r = Remove_duplicates_from_2d_array(data_array);
console.log('unique array.');
console.log(r); // [[1,2,3],[4,4,5],[3,4,5]]
You could take a Set for seen sorted string and filter the array by checking the occurences.
function removeDuplicates(array) {
var seen = new Set;
return array.filter(a => (s => !seen.has(s) && seen.add(s))(a.join()));
}
console.log(removeDuplicates([[1, 2, 3], [4, 4, 5], [3, 4, 5], [4, 4, 5]]));
// [[1, 2, 3], [4, 4, 5], [3, 4, 5]]
.as-console-wrapper { max-height: 100% !important; top: 0; }
With an object.
function removeDuplicates(array) {
var seen = {};
return array.filter(v => !seen[v] && (seen[v] = true));
}
console.log(removeDuplicates([[1, 2, 3], [4, 4, 5], [3, 4, 5], [4, 4, 5]]));
// [[1, 2, 3], [4, 4, 5], [3, 4, 5]]
.as-console-wrapper { max-height: 100% !important; top: 0; }
Sets are nice and all, but you may benefit from seeing a simple for-based approach too:
var orig = [[1, 2, 3],
[4, 4, 5],
[3, 4, 5],
[4, 4, 5]];
function undupe(arr){
let ret=[];
for(let candidate of arr){
let found=false;
for(let line of ret){
let linematch=true;
for(let i=0;i<line.length;i++){
if(candidate[i]!==line[i]){
linematch=false; // if one element does not match, the lines are different
break; // and the rest does not matter
}
}
if(linematch){
found=true; // if all elements matched, candidate is a duplicate
break; // remaining lines do not matter
}
}
if(!found){
ret.push(candidate); // candidate is unique, add it to the result
}
}
return ret;
}
console.log(undupe(orig));
candidate loop gets all items in the input array
line loop gets all items from ret array, so the items which are unique so far
i loop compares the actual numbers (one from candidate with the corresponding one from line)
these loop things are slow at large data sizes, so it is a good idea to terminate them as soon as possible. Like when the first elements do not match in a pair of lines, they are different for sure, there is no need to check the rest.
Of course it could be more structured, like
var orig = [[1, 2, 3],
[4, 4, 5],
[3, 4, 5],
[4, 4, 5]];
function linesmatch(line1,line2){
for(let i=0;i<line1.length;i++)
if(line1[i]!==line2[i])
return false;
return true;
}
function isdupe(arr,line){
for(let l of arr)
if(linesmatch(l,line))
return true;
return false;
}
function undupe(arr){
let ret=[];
for(let candidate of arr)
if(!isdupe(ret,candidate))
ret.push(candidate);
return ret;
}
console.log(undupe(orig));
This would be the more textbook-like variant with small, readable functions built on top of each other.
You may Array.prototype.reduce() source array doing Array.prototype.find()'ing duplicates along the way:
const src = [[1,2,3],[4,4,5],[3,4,5],[4,4,5]],
arrsAreEqual = (a1,a2) => a1.sort().join('|') === a2.sort().join('|'),
dedupe = src.reduce((r,a) =>
(!r.find(ra => arrsAreEqual(a,ra)) && r.push(a), r), [])
console.log(JSON.stringify(dedupe))
.as-console-wrapper{min-height:100%;}
here is my fixed simple version of duplicate remover based on for loop
function Remove_duplicates_from_2d_array(data_array) {
var unique_array = [];
if (data_array.length > 0) {
let unique_index_counter = 0;
// loop on target array
for (var a = 0; a < data_array.length; a++) {
// if have same indexs , skip
if (a === unique_index_counter) {
continue;
}
// compare both indexes
if (data_array[unique_index_counter].join(',') == data_array[a].join(',') ) {
data_array.splice(a, 1); // remove that a index
a = 0; // reset for loop as splice will rebuilt array
continue;
}
// a will be equal to data_array length incase there is no match found
else if ( (data_array.length != 0 && a == data_array.length - 1) ) {
unique_array.push(data_array[unique_index_counter]); // push unique index to unique array
data_array.splice(unique_index_counter, 1); // remove that a index
a = 0; // reset for loop as splice will rebuilt array
}
} // for end
// by now one unique element will be still left in source arrays
unique_array.push(data_array[0]); // push unique index to unique array
return unique_array;
} else {
return [];
}
}
var a1 = [1, 2, 3];
b1 = [4, 4, 5];
c1 = [3, 4, 5];
d1 = [4, 4, 5];
var data_array = [];
data_array.push(a1);
data_array.push(b1);
data_array.push(c1);
data_array.push(d1);
console.log('original array.');
console.log(data_array);
var r = Remove_duplicates_from_2d_array(data_array);
console.log('unique array.');
console.log(r); // [[1,2,3],[4,4,5],[3,4,5]]
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)