This question already has answers here:
Copy array by value
(39 answers)
Closed 3 years ago.
I've an array, and I want to create 2 differents variables from the same array but this variables must have different result. For example, an array of string : the first variable must contain this array, and the other variable must contains this values but sorted. But it's not working :
var letters = ['b', 'c', 'a']; // datas
const lettersUnsorted = letters; // i want the array like the var "letters"
const letterSorted = letters.sort(); // i want the array like the var "letters" but sorted
console.log(letterSorted); // OK => returns: ["a", "b", "c"]
console.log(lettersUnsorted); // KO => returns: ["a", "b", "c"] instead of ['b', 'c', 'a']
You should make a copy the array first because sort() method modifies the original array. You can make the copy of the array using slice()
var letters = ['b', 'c', 'a'];
const lettersUnsorted = letters;
const letterSorted = letters.slice().sort(); //this line is changed
console.log(letterSorted);
console.log(lettersUnsorted);
This is because the reference to the original letters array is maintained.
lettersUnsorted and letterSorted are both referencing to the letters variable. This is because letters is an array (which is technically an object), and in JavaScript, assigning another variable to it will result in assignment by reference (rather than assignment by value). Therefore, any operations or mutation to letters will result in both lettersUnsorted and letterSorted in having the same result as letters, due to the reference to letter.
You should create a shallow clone of the original letters array. This will allow you to safely carry out any mutation without affecting the other array. We can achieve this using ES6's spread syntax.
const letters = ['b', 'c', 'a'];
const lettersClone = [...letters].sort();
console.log(letters);
console.log(lettersClone);
you can use concat also.
var letters = ['b', 'c', 'a'];
const lettersUnsorted = letters;
const letterssorted = ([].concat(letters)).sort();
Related
If I normally use for of loop and use iterator as entries that situation look like this:
var a = ['a', 'b', 'c'];
var iterator = a.entries();
for (let e of iterator) {
console.log(e);
}
// [0, 'a']
// [1, 'b']
// [2, 'c']
iterator: will be the entire array that contain all elements key/value pair. Key will be the index.
e: will be an element in the array
BUT what is this??????
let text = "A A A";
let splitwords = text.split(" ");
let words = [];
for (const [, item] of splitwords.entries()) {
words.push(item.split(""));
}
console.log(`This is the words: ${words}`);
what meaning the [, item] part???
and why should i use this pattern?
text.split("") do exactly same thing or not?
(Otherwise I try solve an text animation problem and this inherit from that code:
framer motion text animation )
Thank you
PS: I know this is an array destructing my main question that why????
for (const [, item] of splitwords.entries()) {
words.push(item.split(""));
}
[, item] is called array destructing, and the reason for that is because of entries in splitwords.entries(). The result of that array is like this [0, "a"],[1, "b"] (the first item is an index, and the second item is value), but in this case, they don't use an index, so the declaration is like [,item] (If they want to use it, the code can be [index, item]).
Without using an index, they can implement this way
for (const item of splitwords) { //remove entries and array destructing
words.push(item.split(""));
}
and why should I use this pattern?
Well, I think this is just their code style to use for of for collecting both index and value together. It depends on you need an index or not.
words.push(item.split("")) is different from the above case, they try to make the entire word "Hello" into characters ["H","e","l","l","o"] for the animation, so the final result of words can be
[
["F","r","a","m","e"],
["M","o","t","i","o","n"],
...
]
It's just a way to skip destructuring the first element in the array. You are basically saying that you are not interested in the first array item.
Since the entries() method returns a new Array Iterator object that contains the key/value pairs for each index in the array.
const foo = ['a', 'b', 'c'];
for (const [, item] of foo.entries()) {
// item would be 'a', 'b', 'c'
}
for (const [index, item] of foo.entries()) {
// item would be 'a', 'b', 'c'
// index would be 0, 1, 2
}
This is a destructuring assignment.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Array.prototype.entries() returns an array of 2 elements for the index and the item itself for each array item.
So in this expression the index is assign to nothing (because there is no variable declared before the comma) and the item is assigned to item.
Example
const ar = [1,2]
const [,value2]=ar
console.log(value2)
const [value1,]=ar
console.log(value1)
const [v1, v2] = ar
console.log(v1, v2)
For the item.split("") it just seems useless, the result would be the same in the present case with just words.push(item) since each word is just one letter... If the words were more than one letter this would just store each letter separately in the words array. Which could maybe be called letters I guess...
Edit:
for the "why use this pattern" question. In the present case, again it just seems useless. The index is not used so calling entries just don't seems relevant.
I don't know if you 'should' use this pattern, but if you want an explanation of what it is, it's like
for(let temp of splitwords.entries()){
const [, item] = temp;
words.push(item.split('');
}
And then const [, item] = temp; is basically the same as const item = temp[1].
Due to how ".entries()" work for an array (giving [index, value]), since the index is ignored by the destructuring, the resulting item is just the value. So, I don't think the result is any different from the following:
for (const item of splitwords) {
words.push(item.split(""));
}
Maybe they were preparing for the future, in case the index becomes important some day.
Has any vuejs veteran experience this on VueJS(v2) where you have 2 arrays on a Component, and you push a value to the 1st array and the 2nd array gets the value also WITHOUT TOUCHING IT.
This is the first time I've encountered this, fyi I've been using VueJS for more than 2yrs already.
Additional information I have a VERY VERY similar component with exactly the same data variables and it doesn't happen, only on the 2nd Component.
array1 = [];
array2 = [];
array1.push('gether');
output should be
array1 = ['gether'];
array2 = [];
WHAT ACTUALLY HAPPENS
array1 = ['gether'];
array2 = ['gether'];
I've also played with the Google DevTools Vue Debugger.
Adding an entry on the array1 ONLY also adds the value on the array2.
kinda mind boggling
Because arrays in JS are reference values, so when you try to copy it using the = it will only copy the reference to the original array and not the value of the array. To create a real copy of an array, you need to copy over the value of the array under a new value variable. That way this new array does not reference to the old array address in memory.
To achieve this you can use array.slice() method as it creates a new array not a mere reference !
See Example and understand difference =>
Using reference (=)
let array = ["some text"]
// Making it equal to main array and using reference to copy
array1 = array;
array2 = array;
array1.push('gether');
console.log(array2)
Using array.slice() to clone
let array = ["some text"]
// Making it equal to main array and using slice to copy
array1 = array.slice();
array2 = array.slice();
array1.push('gether');
console.log(array2)
When you make two arrays equal to the same value, you make them equal by reference.
So
foo = ['a', 'b', 'z']
array1 = foo;
array2 = foo;
array1.push('d');
console.log(array2) //Outputs: ['a', 'b', 'c', 'd']
Is expected behaviour.
However that is not the same as the given example in your question. Run snippet below to see the difference.
To avoid this, you can use slice() to create a copy of the original array. I added an example to the code snippet.
let foo = ["a", "b"];
let array1 = foo;
let array2 = foo;
array2.push("c");
console.log(foo); // Outputs ["a", "b", "c"]
console.log(array1); // Outputs ["a", "b", "c"]
let array3 = [];
let array4 = [];
array4.push("a");
console.log(array3); // Outputs []
console.log(array4); // Outputs ["a"]
let bar = ["a", "b"];
let array5 = bar.slice();
bar.push("c");
console.log(bar); // Outputs ["a", "b", "c"]
console.log(array5); // Outputs ["a", "b"]
This question already has answers here:
Array intersection (set-theoretic) with Array.prototype.reduce
(3 answers)
Closed 1 year ago.
Let's say that I have the following multidimensional array :
const arrayOfValues = [
['a', 'b', 'c'],
['a', 'c'],
['c']
];
I would like to create a new array containing only the values that are present at every index of my original multidimensional array. So I would end up with the following array in this case :
['c']
I'm having trouble finding a way to do so as I am not too familiar with javascript. I'm guessing I have to apply some sort of filtering (probably map over the array and apply a specific condition) but I'm not sure how to go about it.
You can use Array#reduce along with Array#filter.
const arr = [
['a', 'b', 'c'],
['a', 'c'],
['c']
];
let res = arr.reduce((acc,curr)=>acc.filter(x=>curr.includes(x)));
console.log(res);
Start with a persistent variable that starts with the values in the first subarray. Then iterate over each other subarray, reassigning that variable to a filtered version of the subarray currently being iterated over, filtering by whether the item is contained both in the previous subarray and the current one:
const arrayOfValues = [
['a', 'b', 'c'],
['a', 'c'],
['c']
];
let previous = arrayOfValues[0];
arrayOfValues.slice(1).forEach((subarr) => {
previous = subarr.filter(
item => previous.includes(item)
);
});
console.log(previous);
Is there an easy way of getting an order difference of two string arrays?
var A = ['a', 'b'];
var B = ['b', 'a'];
by comparing these two is there an easy way of finding out that they swapped index? i couldnt find anything helpful online and
i dont really want to go the long and hard way about it as the array i am using is quite big. Using dragtable to reorder columns of my datatable and i am constantly pushing data to it so whenever an order changes i want the specific data to go into their designated column that is why i need it, thanks!
You could iterate over one array and compare the index of the current value to the index of same value in the other given array. If both mismatch, you can create map, containing a mismatch matrix for every value which you can use for further computation. See https://jsfiddle.net/f2jL46ke/
const arr1 = ['a', 'b', 'c']
const arr2 = ['b', 'c', 'a']
// I am assuming, that both arrays have an equal length
const differences = arr1.reduce((store, value) => {
const arr1Index = arr1.indexOf(value)
const arr2Index = arr2.indexOf(value)
if(arr1Index !== arr2Index) {
store[value] = [arr1Index, arr2Index]
}
return store
}, {})
console.log(differences)
With that approach you know A) what strings weren't at the same position in the arrays and B) where they are located in both arrays.
You will simply use sort() method
var A = ['a', 'b'];
var B = ['b', 'a'];
B=B.sort();
and B.sort() retutn ['a', 'b'];
I am trying to remove punctuation from each string within an array, but this problem would exist for trying to delete any type of character within strings within an array.
I have attempted to create 3 loops:
The first loop iterates over each item in arrayA that I'm aiming to edit.
The second loop iterates through each character in each string in arrayA.
The third loop checks whether the character in arrayA matches any character in arrayB, and deletes it if it does.
Nothing is being deleted however, and I'm not sure why.
This is my code so far:
let arrayA = ['abc', 'def', 'ghi'];
let arrayB = ['a', 'e', 'i', 'o', 'u'];
arrayA.forEach((item) => {
for (let i=0; i < item.length; i++) {
for (let arrayBIndex = 0; arrayBIndex < arrayB.length; arrayBIndex++) {
item.replace(arrayB[arrayBIndex], '');
};
};
});
console.log(arrayA);
I have searched for other questions dealing with this, but I haven't been able to find any answers, specifically where the elements to delete are contained in another list. Thank you for your help.
You can generate regular expression using arrayB and then using array#map iterate through each word in arrayA and use string#replace to get rid of words from arrayB.
let arrayA = ['abc', 'def', 'ghi'],
arrayB = ['a', 'e', 'i', 'o', 'u'],
regExp = new RegExp(arrayB.join('|'), 'g'),
result = arrayA.map(word => word.replace(regExp, ''));
console.log(result);
Use Array.prototype.splice(), take a look on this:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
If you wish to follow with arrays, I would suggest to transform your strings into an array of characters and using array filter operator.
However you can probably achieve what you want to do with regular expressions
const arrayA = ['abc', 'def', 'ghi'];
const arrayB = ['a', 'e', 'i', 'o', 'u'];
const result = arrayA
.map(s => [...s]) // array of chars
.map(chars => chars.filter(ch=>!arrayB.includes(ch)).join(''))//filter out invalid char and transform back into string
console.log(result)
const result = arrayA.map(item => {
let replaced = "";
for(const char of item)
if(!arrayB.includes(char))
replaced += char;
return replaced;
});
Strings are immutable. Every mutation returns a new string instead of mutating the original.