I have 2 arrays: A and B, when I change one both change. Is there a way to edit one without changing the other one.
a = [[0,0,0,0,0],[0,0,0,0,0]]
b = [[1,2,3,4,5],[6,7,8,9,10]]
a = b.slice(0)
a[0][0] = 10
console.log(a) /* [[10,2,3,4,5],[6,7,8,9,10]] */
console.log(b) /* [[10,2,3,4,5],[6,7,8,9,10]] */
The a is fine but I need b to stay [[1,2,3,4,5],[6,7,8,9,10]]
When you do splice, you change the reference of a and b, however, the reference of arrays in array b still share references, hence, update your code to following. Use Array.map
a = [[0,0,0,0,0],[0,0,0,0,0]]
b = [[1,2,3,4,5],[6,7,8,9,10]]
a = b.map(x => [...x])
a[0][0] = 10
console.log(a) /* [[10,2,3,4,5],[6,7,8,9,10]] */
console.log(b) /* [[1,2,3,4,5],[6,7,8,9,10]] */
You can use map to slice each array.
a = [[0,0,0,0,0],[0,0,0,0,0]]
b = [[1,2,3,4,5],[6,7,8,9,10]]
a = b.map(o=>o.slice(0));
a[0][0] = 10
console.log(a);
console.log(b);
Doc: map()
You take a shallow copy with Array#slice, which means nested arrays are taken by their object reference.
You could use Array#map with a check for arrays and map these recursively.
const deep = a => Array.isArray(a) ? a.map(deep) : a;
var a = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]],
b = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]];
a = b.map(deep);
a[0][0] = 10;
console.log(a);
console.log(b);
.as-console-wrapper { max-height: 100% !important; top: 0; }
slice(), like Object.freeze() have a shallow scope, so this works:
var a = [1,2,3,4];
var b = a.slice(0);
a[0] = 10;
console.log(b); // [1, 2, 3]
console.log(a); // [10, 2, 3, 4]
But this doesn't work:
var a = [[0,0,0,0,0],[0,0,0,0,0]]; //multidimensional!
var b = [[1,2,3,4,5],[6,7,8,9,10]];
a = b.slice(0);
a[0][0] = 10;
console.log(a);
console.log(b);
Then, the key is go deep with slice(), for or something, Here an example using for:
var a = [];
for (var i = 0, len = b.length; i < len; i++) {
a[i] = b[i].slice();
}
Keep in mind that const won't work:
var a = [[0,0,0,0,0],[0,0,0,0,0]];
const b = [[1,2,3,4,5],[6,7,8,9,10]];// doesn't work
var a = b.slice(0);
a[0][0] = 10; // a changes b
console.log(a);
console.log(b);
Related
I have around 30 values stored as variables:
var a = 1,
b = 2,
c = 3,
...
z = 26,
aa = 27,
ab = 28;
that I want to scale. I do so using an array:
array = [a, b, c];
var scale = 5;
for (var i = 0; i < array.length; i++){
array[i] = array[i] * scale; // Some simple arithmetic
}
To get the new scaled value, I need to reassign my variables.
var a = array[0],
b = array[1],
c = array[2],
...
z = array[26],
aa = array[27],
ab = array[28];
This is cumbersome, even if I use destructuring assignment. What is a better way to manage all the information I have?
Using plain variables you won‘t find a smarter way. I‘d suggest to use objects instead as arrays are anonymous because you access the content by index instead of a name:
let groupA = {
a: 1,
b: 2,
c: 3
}
You can then iterate and multiply via
for (let key in groupA) {
if (groupA.hasOwnProperty(key) {
groupA[key] *= 5;
}
}
but you still can access each field individually
console.log(groupA.a);
You have to reassign anyway, but you can do it in a more concise way:
let a = 1,
b = 2,
c = 3;
([a, b, c] = [a, b, c].map(v => v * 5));
console.log(b);
The following code produces (in Chrome javascript console)
a: (3) [1, 2, 3] b: (4) [1, 2, 3, 99] c: 4
I expected c to look like b. Why doesn't it?
function snafu(){
var a = [1,2,3];
var b = a.slice();
var c = a.slice().push(99);
b.push(99);
console.log("a:",a," b:",b," c:",c);
}
Array.push() gives you value of Array.length and not array itself
var a = [];
var b = a.push(8); /* returns length of array after pushing value into array */
console.log('a = ', a, ', b = ', b);
Well, remember Array.slice() will return you new Array. So while pushing it on slice(), it'll return you length of the array.
function snafu(){
var a = [1,2,3];
var b = a.slice();
var c = a.slice();
c.push(99);
b.push(99);
console.log("a:",a," b:",b," c:",c);
}
snafu();
variable c will give you new Array so you can do whatever you want with c.
That's it. Easy!!!!
I have two one-dimensional arrays, a and b. a has values and b is empty. The length of a is an even number. I'd like to remove every other value from a and move them to b, in the same order as they were placed in a.
var a = [1, 2, 3, 4, 5, 6], b = [];
becomes
var a = [1, 3, 5], b = [2, 4, 6];
I figured that filter would do the trick but I'm not that happy with the performance of it since the average length of a is 300-400.
b = a.filter((i, idx) => {
return idx % 2 == 0;
});
a = a.filter((i, idx) => {
return idx % 2 == 1;
});
I've also been looking at lodash to see if that library had anything that might help me and the only function that's near what I'm looking for is _.chunk(array, \[size=1\]).
I appreciate any and all help to help me figure out a better, faster way to do this.
Since you mentioned lodash you could do this with _.partition:
let a = [1, 2, 3, 4, 5, 6];
let b = [];
let i = -1;
[a, b] = _.partition(a, (item) => i++ % 2);
console.log(a);
console.log(b);
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
Partition's predicate is the identity function, which doesn't include the index of the item, so this comes with a compromise of an external index i.
Of course, you could always wrap this functionality into it's own function:
const splitEvenOdd = (array, i = -1) => _.partition(array, (item) => i++ % 2);
let a = [1, 2, 3, 4, 5, 6];
let b = [];
[a, b] = splitEvenOdd(a);
console.log(a);
console.log(b);
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
Vanilla JS ES5, simple and clean.
var a = [1, 2, 3, 4, 5, 6], b = [];
for(var i = a.length-1; i >= 0; i--) {
if(i % 2 === 1) {
b.unshift(a.splice(i, 1)[0])
}
}
Basically, it is iterating through a backwards, and if the condition is true splicing the item und adding it as first item of b.
To loop through the source once, the values can be added to a specific array depending on the index. For example:
const source = [1, 2, 3, 4, 5, 6];
let arrs = [[],[]];
for(let i = 0; i< source.length; i++)
arrs[i%2].push(source[i]);
let [a,b] = arrs;
console.log(a);
console.log(b);
Alternatively, if it's important to alter the original arrays, a can be filled in a direct iteration, since the index being processed is always ahead of the one being filled:
let a = [1, 2, 3, 4, 5, 6], b= [];
for(let i = 0; i< a.length; i++)
(i % 2 ? b : a)[Math.floor(i/2)] = a[i];
a.splice(a.length/2);
console.log(a);
console.log(b);
The best performance you can get for this is 0(n) or linear time since you have to iterate through the entire array. What may help is reducing the number of loops
var a=[];
var b=[];
function splitArray(arr)
{
for (var i=0;i<arr.length;++i)
{
if (arr[i]%2 == 0)
b.push(arr[i]);
else
a.push(arr[i]);
}
}
What this does is reduces the number of times you have to iterate through the original array from 2 to 1
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));
}
Coming from a matlab background, I am trying to replicate the following scenario in Javascript
A = [1, 2, 3, 4, 5];
B = 4;
C = A == B;
answer => C = [0, 0, 0, 1, 0]
In other words, it generates a logical array where only the value compared is set to 1. I can do this using a loop but I was wondering if there a 1 liner solution to this in javascript?
You can use the map() function to do something similar to what you were looking for:
var A = [1, 2, 3, 4, 5];
var B = 4;
var C = function (x) { return +(x === B); };
var answer = A.map(C);
var C = x => +(x === B); would look cleaner, but that's ES6 code (experimental).
About the fanciest you could get would be
var C = A.map(function(v) { return v == B ? 1 : 0; });
That's supported in newer JavaScript runtime systems.
In JavaScript it'd probably be more idiomatic to prefer a result array containing boolean values:
var C = A.map(function(v) { return v == B; });
There's not a one-liner, but using Array.map can get you pretty close to what you want:
var a = [1, 2, 3, 4, 5];
var b = 4;
var c = a.map(function(item) { return item === b? 1: 0; });
console.log(c);
Fiddle
Note map isn't supported by older browsers, the MDN link above has polyfil code or you can include any number of libraries that provide something equivalent (e.g. jQuery has a .map() function).
You could write your own function :
function equals(a, b) {
var result = [];
while (result.length < a.length) {
result.push(+(a[result.length] == b));
}
return result;
}
var A = [1, 2, 3, 4, 5];
var B = 4;
var C = equals(A, B); // [0, 0, 0, 1, 0]