Clone array of objects into itself - javascript

This is my source array (e.g. with 20 elements):
var myArray= $('.my-selector').clone().toArray();
I want to clone the whole array into itself. The new array should have 40 elements (each element is existing "twice"). Like this:
myNewArray = myArray.concat($('.my-selector').clone().toArray())
But it seems that the new arrays elements are references to the original and no real clones.

Updated answer.
#JKB, I have updated my answer based on your recent comment on my old answer. I think the code you have posted in your question is actually working fine. I am using 3 elements to demo this, instead of the original 20, but the same logic applies.
I have quoted you in code comments in the code snippets, from your original question, as well as your recent comment on my old answer. Please read through them.
// "The source are jQuery objects" ~ JKB
var source = $('.my-selector')
/* "This source should be cloned into an array" - JKB
I am Copying this from your original code. */
var myArray = $('.my-selector').clone().toArray()
/* "Now i want to increase the arrays size by copying its content into itself, after that the array should contain 20 objects (each object twice)" - JKB
Our array should contain 6, since we're cloning 3 elements onto itself. Copying this again from your original code. */
var myNewArray = myArray.concat($('.my-selector').clone().toArray())
// "BUT: Now this objects should be inserted back into another DOM place (not into their original place)." - JKB
$('#anotherPlace').append(myNewArray)
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<div class="my-selector">first</div>
<div class="my-selector">second</div>
<div class="my-selector">third</div>
<div id="anotherPlace" style="background:red"></div>
But it seems that the new arrays elements are references to the
original and no real clones.
They aren't, that's why we see 2 copies of each - first, second and third in the red background div. Is this what you were looking for, or did I miss something obvious?

You can use the concat method on javascript from mdn.
The concat() method is used to merge two or more arrays. This method
does not change the existing arrays, but instead returns a new array.
var arr = ["test1", "test2", "test3"];
arr = arr.concat(arr);
hope this helps

using ES6 spread operator you can do:
const arr = [1, 2, 3]
const doubledArr = [...arr, ...arr]
console.log(doubledArr) // [1, 2, 3, 1, 2, 3]

I assume you want the objects to be cloned sequentially, so you could just concatenate the array with a clone of itself using:
arr = arr.concat(arr)

Related

Javascript: Subarrays contain reference to other arrays even though parent is its own array? [duplicate]

This question already has answers here:
How do you clone an array of objects in JavaScript?
(40 answers)
What is the most efficient way to deep clone an object in JavaScript?
(67 answers)
Closed 4 years ago.
OK.
Let me try to say this in some sort of comprehensible manner. I'm an amateur programmer writing my own take on a neural network in javascript. (Without having seen the code for a neural network before)
I was having problems with an array changing when I was trying to change a copy of the array. (Not the original)
I soon realized after rereading what I'd written that when you assign an identifier to an array it doesn't make the identifier a new object with a copy of the array. Instead, it makes a reference to the original array object, for example:
var arr = [1,2,3];
var arr2 = arr;
arr2[0] = 9;
alert(arr);
//Alerts "9,2,3"
With this mind, I googled and found a quick solution:
var arr = [1,2,3];
var arr2 = arr.slice();
arr2[0] = 9;
alert(arr);
//Alerts "1,2,3"
So I changed this in my actual project expecting to see my work completed, but no! I was getting the exact results as before where my array was changing even though it was not supposed to.
After much effort at debugging, I finally worked out that the problem here is that I have a large array of subarrays, which in turn have subarrays.
In code this looks like:
var arr = [
[[1],[2]],
[[4],[5]],
[[7],[8]]
];
As you can see, there is one big array that contains 3 smaller arrays, each of which contains two even smaller arrays, each of which contains a number.
In my project, it's more complicated than this and has a couple more layers but this is a decent representation.
So what did I expect to happen?
var arr = [
[[1],[2]],
[[4],[5]],
[[7],[8]]
];
var other = arr.slice();
other[0][0][0] = "Uh Oh";
alert(arr);
//Outputs "1,2,3,4,5,6,7,8"
What actually happened?
alert(arr);
//Outputs "Uh Oh,2,3,4,5,6,7,8"
Why does this happen?
How can I fix it?
Thanks in advance.
Try following
var arr = [
[[1],[2]],
[[4],[5]],
[[7],[8]]
];
var other = JSON.parse(JSON.stringify(arr));
other[0][0][0] = "Uh Oh";
console.log(arr);
Reasoning
arr.slice() creates different reference for the array, however, any child object/array will still continue to hold the same reference. But you need to change the references of the child object/array as well, for that convert it into a string and then back to object - It will create different references for all the objects.

How to rank array elements?

I tried searching using many different keywords but I'm unable to get the result I'm looking for.
I've created a table with five values as such: 10, 3, 5, 4, 2
I have a row on top of the table which shows the rank.
So, above 10, it should say "5"
Above 3, it should say "2"
Above 5, it should say "4"
Above 4, it should say "3"
Above 2, it should say "1"
I can take care of the tabular column. It is the main script that I don't understand.
I thought I can create a duplicate array of the original one and sort the duplicate - Then compare both original and duplicate to rank them. It turns out that when I sort the duplicate array, the original is also sorted.
I thought I can create 2 duplicate arrays and not touch the original one. It still sorts all of the arrays. How can I do this then?
It sounds like you are looking for how to clone or deep copy an array. When you do something like:
var a = [5,4,3,2,1]
var b = a;
Array b is set to refer to array a. If you, however, take a slice or do something else to get a copy of the data (not something refering to the actual structure), you can clone the array. So something like:
var a = [5,4,3,2,1]
var b = a.slice(0);
will give you an array b that won't change if you change a. See articles like this for more information.
You can duplicate the array using spread. From there you can do a simple sort() to get the rank you're trying to achieve:
const arr = [10, 3, 5, 4, 2];
const sortedArr = [...arr].sort((a,b) => a > b);
console.log(sortedArr);

Reversing an array which is a value in object in Javascript

I am trying to reverse an array which is an element in an object.
colorKey = {
"2m":["#ffffff","#000000"]
}
colorKey["2mi"] = colorKey["2m"];
Array.reverse(colorKey["2mi"])
This is not working and returning colorKey["2mi"] the same as colorKey["2m"]. When I run the same command in developer console in browser, it reverses successfully. Where is the problem?
This is no static method off Array called reverse. reverse is an instance method (Array.prototype.reverse) off the Array object, so the instance of the Array must be the caller.
This solves your problem:
colorKey = {
"2m":["#ffffff","#000000"]
}
colorKey["2mi"] = colorKey["2m"];
colorKey["2mi"].reverse();
Output:
["#000000", "#ffffff"]
Calling reverse() for an array mutates it (reverse is in place - a new array is not created). What you want, apparently, is to have a reversed copy of the array. Basically, create a new array with the same values and then reverse it.
var a = [1, 2], b;
b = a.slice(0).reverse();
Slice creates a new array with the same elements (but remember that it is not cloning the elements).
#Rajat Aggarwal
What you are asking for, is to clone your previous array in reverse order.
The only trivial part of it would be reversing it. Because there is no way of cloning Objects and Arrays, nor a general method that you could write down as a function to be using it universally.
This specific array from the sample you provided can be cloned easily because it is flat and it only contains primitives. But the solution to it, will be exactly as specific as the sample array provided.
A specific solution to this task would be to use a plain coma-separated string of successive values and convert that to specific arrays of their corresponding primitive values.:
var colors = "#ffffff,#000000";
var colorKey = {
"2m":colors.split(","),
"2mi":colors.split(",").reverse()
}
which will yield you a:
>> colorKey
{
2m : #ffffff,#000000,
2mi : #000000,#ffffff
}

Merging two arrays of objects

I have a bit of a problem where I am struggling on for a pretty long time now. I have two arrays:
var arr1 = [{"x":1,"y":1,"value":null},{"x":2,"y":1,"value":null},{"x":3,"y":1,"value":null},{"x":4,"y":1,"value":null},{"x":5,"y":1,"value":null},{"x":1,"y":2,"value":null},{"x":2,"y":2,"value":null},{"x":3,"y":2,"value":null},{"x":4,"y":2,"value":null},{"x":5,"y":2,"value":null},{"x":1,"y":3,"value":null},{"x":2,"y":3,"value":null},{"x":3,"y":3,"value":null},{"x":4,"y":3,"value":null},{"x":5,"y":3,"value":null},{"x":1,"y":4,"value":null},{"x":2,"y":4,"value":null},{"x":3,"y":4,"value":null},{"x":4,"y":4,"value":null},{"x":5,"y":4,"value":null},{"x":1,"y":5,"value":null},{"x":2,"y":5,"value":null},{"x":3,"y":5,"value":null},{"x":4,"y":5,"value":null},{"x":5,"y":5,"value":null}];
var arr2 = [{"x":1,"y":1,"value":13},{"x":1,"y":3,"value":3},{"x":2,"y":2,"value":146},{"x":2,"y":3,"value":44},{"x":2,"y":4,"value":42},{"x":2,"y":5,"value":5},{"x":3,"y":2,"value":14},{"x":3,"y":3,"value":57},{"x":3,"y":4,"value":23},{"x":3,"y":5,"value":15},{"x":4,"y":2,"value":1},{"x":4,"y":3,"value":4},{"x":4,"y":4,"value":8},{"x":4,"y":5,"value":1},{"x":5,"y":4,"value":1},{"x":5,"y":5,"value":8}];
Where arr1 always contains 25 objects and arr2 contains a variable number of objects, but they are always formatted the same.
How do I combine both arrays into one, where for example:
{"x":1,"y":1,"value":null} from arr1 will be {"x":1,"y":1,"value":13} as a result, but {"x":2,"y":1,"value":null} from arr1 will stay the same, since arr2 does not have this object.
After merging it would be most ideal to have an array of 25 objects, where the field "value" is filled from the objects out of arr2.
EDIT
Alright, since I am getting a lot of downvotes, you can find my code on JSFiddle
Any help is very much appreciated!
You can achieve this using jQuery extend if that's an option.
var extendedArray = $.extend({}, arr1, arr2);
The code above will create a new object for you which will contain what you requested. If you don't want a new object, then just use
$.extend(arr1, arr2);
See the docs mentioned above for more info (like deep extending, etc..).

Is it possible to chain array.push() in Javascript?

I have 3 separate arrays and I'm looking to load them all into to a single array. Am I able to use .push() several arrays into one? Is something like this possible?
var activeMembers=[]; // Active Users
var noactiveMsg=[]; // Non-Active Users with a Pending Message
var noactiveNomsg=[]; // Non-Active Users without a Pending Message
var chatCenterMembers=[]; // Final Array of Chat Center Members
chatCenterMembers.push(activeMembers).push(noactiveMsg).push(noactiveNomsg);
Is there a way to chain .push()?
You're looking for the (vanilla) JavaScript method Array.concat().
Returns a new array comprised of this array joined with other array(s) and/or value(s).
Example, following your code:
chatCenterMembers = chatCenterMembers
.concat(activeMembers)
.concat(noactiveMsg)
.concat(noactiveNomsg);
chatCenterMembers.push(activeMembers,noactiveMsg,noactiveNomsg)
This question is quite confusing. First of all, the question seems to be asking for a way to combine multiple arrays into one single array containing the elements of all the arrays. However, the accepted answer provides a solution for creating an array of arrays. Since the text in the question suggests merging the elements of multiple arrays into one array while the code example uses push with arrays as arguments, it's quite ambigious what the OP wants.
Furthermore, several answers have suggested using concat. While that fulfills the requirement of returning the resulting array after adding the provided element, and is fine for small sets of data and/or where performance and memory is not an issue, it's inefficient if dealing with large arrays, since each concat operation will allocate a new array, copy all the elements of the old array into it, then copy all the elements of the provided array into it, and dereference the old array (as opposed to simply adding elements to the same array object).
Consider calling concat N times, adding C elements each time:
allocate new array, copy C elements
allocate new array, copy 2 * C elements
allocate new array, copy 3 * C elements
...
A different approach would be to create your own method, either as a separate function or adding it to the Array prototype:
Array.prototype.append = function(e) {
this.push(e);
return this;
}
With this, you could do
[1, 2, 3].append(4).append(5).append(6)
without allocating more than one array object in total.
It could perhaps also be mentioned that with ES2015, the spread operator can be used to add all the elements of an array to another array using push:
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
arr1.push(...arr2); // arr1 is now [1, 2, 3, 4, 5, 6]
This will however not fulfill the requirement of returning the resulting array for chaining, but the append method above could be used to merge multiple arrays like this:
chatCenterMembers = activeMembers.append(...noactiveMsg).append(...noactiveNomsg);
You can do it instead with .concat().
var chatCenterMembers=[];
chatCenterMembers = chatCenterMembers.concat(activeMembers, noactiveMsg, noactiveNomsg);
Since on one else has posted it:
var chatCenterMembers = activeMembers.concat(noactiveMsg, noactiveNomsg);
push AND unshift chaining
I actually came here looking for both but didn't see any good answer so far for unshift so I'll note that here as well.
push chaining is straight forward
const list = ['hi', 'there']
.concat(['buddy'])
// list is now ['hi', 'there', 'buddy']
but unshift chaining is weird
// need to use concat + map to do unshift chaining
const list = ['hi', 'there']
.concat(['buddy'])
.map((e, i, a) => i == 0 ? a[a.length - 1] : a[i-1])
// list is now ['buddy', 'hi', 'there']
As you can see using map there is a 3rd param given for the array you are using so this gives you power to do all sorts of odd things.

Categories

Resources