Javascript array referencing an array position (not an element) - javascript

UPDATE:
Many asked why not using [arr[0], arr[1]]. The problem is I have to pass this array to a method, which I don't have access Angular Material Table. And I don't want to call the method over and over again.
I already processed the arr array and I don't want to process pointer array to reflect the new data, which I already know where it is.
The Nina Scholz answer seems to solve the problem.
Is there a way to use "pointers" like C in Javascript?
What I want to do is:
I have an array with objects
const arr = [
{prop: 3},
{prop: 4},
];
And I want to have an array to point to the positions of this array
const pointer = [arr[0], arr[1]]; // I want pointer to point to be an array containing the first and second elements of arr
This will get a reference to the {prop: 3} and {prop: 4} objects, which is not what I want, because, if I do:
arr.splice(0, 0, {prop: 1}); // arr => [{prop:1},{prop:3},{prop:4}]
console.log(pointer); // [{prop: 3},{prop: 4}]
As you can see, pointer holds a reference to the objects {prop:3} and {prop:4}.
How can I achieve pointer to hold reference to the position 0 of the array, instead of the object stored in it? So, on this example, pointer => [{prop:1},{prop:3}]?
I can't call pointer = [arr[0], arr[1]] all the time because arr will change constantly and asynchronously.
Is there a "reactive" way to handle arrays?

If your pointers are always to the same array, you can simply store the indexes.
const pointer = [0, 1];
Then you would use:
console.log(pointer.map(ptr => arr[ptr]));
If your pointers can point to different arrays, you can make the elements of pointer be objects that contain references to the array along with their indexes.
const pointer = [{a: arr, i: 0}, {a: arr1, i: 1}];
console.log(pointer.map(({a, i}) => a[i]));
Interesting aside: several decades ago I used a C implementation for Symbolics Lisp Machines. This is basically how it represented C pointers.

You could use a getter function and return the element of the actual object.
const arr = [{ prop: 3 }, { prop: 4 }];
const pointer = [];
Object.defineProperty(pointer, 0, { get() { return arr[0]; } });
Object.defineProperty(pointer, 1, { get() { return arr[1]; } });
arr.splice(0, 0, { prop: 1 });
console.log(pointer);

You can use a Proxy (not supported by IE) with a get trap:
const arr = [{ prop: 3 }, { prop: 4 }];
const pointer = new Proxy([], {
get(target, prop, receiver) {
// if the prop is a string that can be converted to a number
// return the corresponding value from the arr
if(typeof prop === 'string' && !isNaN(Number(prop))) return arr[target[prop]];
return Reflect.get(target, prop, receiver);
}
});
pointer.push(0, 1);
console.log(pointer);
arr.splice(0, 0, { prop: 1 });
console.log(pointer);

Related

javascript how to avoid numbered object keys to be sorted automatically [duplicate]

Why I met this problem:
I tried to solve an algorithm problem and I need to return the number which appeared most of the times in an array. Like [5,4,3,2,1,1] should return 1.
And also when two number appear same time as the maximum appearance return the one came first. Like [5,5,2,2,1] return 5 because 5 appear first. I use an object to store the appearance of each number. The key is the number itself.
So When the input is [5,5,2,2,1] my object should be
Object {5: 2, 2: 2, 1: 1} but actually I got Object {1: 1, 2: 2, 5: 2}
So When I use for..in to iterate the object I got 2 returned instead of 5 . So that's why I asked this question.
This problem occurs in Chrome console and I'm not sure if this is a common issue:
When I run the following code
var a = {};
a[0]=1;
a[1]=2;
a[2]=3;
a is: Object {0: 1, 1: 2, 2: 3}
But when I reverse the order of assignment like:
var a = {};
a[2]=3;
a[1]=2;
a[0]=1;
a is also:Object {0: 1, 1: 2, 2: 3}
The numeric property automatic sorted in ascending order.
I tried prefix or postfix the numeric property like
var a = {};
a['p'+0]=1;
a['p'+1]=2;
a['p'+2]=3;
console.log(a);//Object {p0: 1, p1: 2, p2: 3}
And this keep the property order. Is this the best way to solve the problem? And is there anyway to prevent this auto sort behavior? Is this only happen in Chrome V8 JavaScript engine? Thank you in advance!
target = {}
target[' ' + key] = value // numeric key
This can prevent automatic sort of Object numeric property.
You really can't rely on order of an object fields in JavaScript, but I can suggest to use Map (ES6/ES2015 standard) if you need to preserve order of your key, value pair object. See the snippet below:
let myObject = new Map();
myObject.set('z', 33);
myObject.set('1', 100);
myObject.set('b', 3);
for (let [key, value] of myObject) {
console.log(key, value);
}
// z 33
// 1 100
// b 3
You are using a JS object, that by definition does not keep order. Think of it as a key => value map.
You should be using an array, that will keep whatever you insert on the index you inserted it into. Think of it as a list.
Also notice that you did not in fact "reverse the order of the assignment", because you inserted elements on the same index every time.
This is an old topic but it is still worth mentioning as it is hard to find a straight explanation in one-minute googling.
I recently had a coding exercise that finding the first occurrence of the least/most frequent integer in an array, it is pretty much the same as your case.
I encountered the same problem as you, having the numeric keys sorted by ASC in JavaScript object, which is not preserving the original order of elements, which is the default behavior in js.
A better way to solve this in ES6 is to use a new data type called: Map
Map can preserve the original order of elements(pairs), and also have the unique key benefit from object.
let map = new Map()
map.set(4, "first") // Map(1) {4 => "first"}
map.set(1, "second") // Map(2) {4 => "first", 1 => "second"}
map.set(2, "third") // Map(3) {4 => "first", 1 => "second", 2 => "third"}
for(let [key, value] of map) {
console.log(key, value)
}
// 4 "first"
// 1 "second"
// 2 "third"
However, using the object data type can also solve the problem, but we need the help of the input array to get back the original order of elements:
function findMostAndLeast(arr) {
let countsMap = {};
let mostFreq = 0;
let leastFreq = arr.length;
let mostFreqEl, leastFreqEl;
for (let i = 0; i < arr.length; i++) {
let el = arr[i];
// Count each occurrence
if (countsMap[el] === undefined) {
countsMap[el] = 1;
} else {
countsMap[el] += 1;
}
}
// Since the object is sorted by keys by default in JS, have to loop again the original array
for (let i = 0; i < arr.length; i++) {
const el = arr[i];
// find the least frequent
if (leastFreq > countsMap[el]) {
leastFreqEl = Number(el);
leastFreq = countsMap[el];
}
// find the most frequent
if (countsMap[el] > mostFreq) {
mostFreqEl = Number(el);
mostFreq = countsMap[el];
}
}
return {
most_frequent: mostFreqEl,
least_frequent: leastFreqEl
}
}
const testData = [6, 1, 3, 2, 4, 7, 8, 9, 10, 4, 4, 4, 10, 1, 1, 1, 1, 6, 6, 6, 6];
console.log(findMostAndLeast(testData)); // { most_frequent: 6, least_frequent: 3 }, it gets 6, 3 instead of 1, 2
To prevent the automatic sort of numeric keys of Object in Javascript, the best way is to tweak the Object keys a little bit.
We can insert an "e" in front of every key name to avoid lexicographical sorting of keys and to get the proper output slice the "e", by using the following code;
object_1 = {
"3": 11,
"2": 12,
"1": 13
}
let automaticSortedKeys = Object.keys(object_1);
console.log(automaticSortedKeys) //["1", "2", "3"]
object_2 = {
"e3": 11,
"e2": 12,
"e1": 13
}
let rawObjectKeys = Object.keys(object_2);
console.log(rawObjectKeys) //["e3", "e2", "e1"]
let properKeys = rawObjectKeys.map(function(element){
return element.slice(1)
});
console.log(properKeys) //["3", "2", "1"]
instead of generating an object like {5: 2, 2: 2, 1: 1}
generate an array to the effect of
[
{key: 5, val: 2},
{key: 2, val: 2},
{key: 1, val: 1}
]
or... keep track of the sort order in a separate value or key
I've stumbled with this issue with our normalised array which keyed with Ids> After did my research, I found out there's no way to fix using the object keys because by default the Javascript is sorting any object key with number when you iterate it.
The solution I've done and it worked for me is to put a 'sortIndex' field and used that to sort the list.
The simplest and the best way to preserve the order of the keys in the array obtained by Object.keys() is to manipulate the Object keys a little bit.
insert a "_" in front of every key name. then run the following code!
myObject = {
_a: 1,
_1: 2,
_2: 3
}
const myObjectRawKeysArray = Object.keys(myObject);
console.log(myObjectRawKeysArray)
//["_a", "_1", "_2"]
const myDesiredKeysArray = myObjectRawKeysArray.map(rawKey => {return rawKey.slice(1)});
console.log(myDesiredKeysArray)
//["a", "1", "2"]
You get the desired order in the array with just a few lines of code. hApPy CoDiNg :)
I came across this same problem, and after search a lot about that, i found out that the solution to prevent this behavior is make key as string.
Like that:
{"a": 2, "b": 2}
you can use Map() in javascript ES6 which will keep the order of the keys insertion.
just trying to solve your problem in an alternative solution, recently like to practise leetcode-like question
function solution(arr) {
const obj = {};
const record = {
value: null,
count: 0
};
for (let i = 0; i < arr.length; i++) {
let current = arr[i];
if (!obj[current]) {
obj[current] = 0;
}
obj[current]++;
if (obj[current] > record.count) {
record.value = current;
record.count = obj[current];
}
}
console.log("mode number: ", record.value);
console.log("mode number count: ", record.count);
}
simply do that while you're working with a numeric array index
data = {}
data[key] = value

set new value for array's value using destructure

i got two noob questions about destructure an array:
1st question: when destructuring an object, I can define a new value or a new key or both. On array, can I add a new value without add a new key?
const obj = {a: undefined, b:2};
const {a = 3, b} = obj;
console.log(a); // 3
I want to know if there is a version of this but with array instead.
2nd question: is it possible to do not provide a default value for objects? Considering that I think that it is not possible to change default values using destructure.
const obj = [1, {a: 1, b:2}, 3, 4];
const [, object, three, four] = obj;
console.log(object); //{a: 1, b:2}
In this example, object returns {a: 1, b:2} but I wanted it change the value instead. Is that possible?
thanks, regards.
You are confusing default values with mutation of values, and assignment of values to variables with mutation of objects. Below is a demo of the default value feature of destructuring, with comments to explain the behavior.
You will see here that in general, destructuring is not designed for mutation of objects, but for extraction of variables and values. And hopefully also get a feel for why it would be undesirable for mutation to be mixed in to it, even if it were possible.
const obj = [1, {a: 1, b:2, 99:'z'}, ,3, 4, {mutateme: 1}];
const [, {a=3,b=4,c=5}, object={a:7,b:7},three, four, object2] = obj;
// a prop has value=1, b has value=2, c is not defined use default value 5
console.log(a,b,c,object);
//object is empty use default value={a:7,b:7}
// obj is unchanged
console.log(obj)
// mutate object2={mutateme:1} by reference (like a pointer)
object2.mutateme=7
// {mutateme: 1=>7}
console.log(obj)
// example of how you could (sort of) mutate inside a destructuring statement
// computed property, obj[1]=obj[3]=99 returns 99,
// so extract property 99 to variable z and mutate object obj at index [1] and [3] to =99
// y will 99 now.
const [y1, {[obj[1]=obj[3]=99]:z},, y2 ] = obj
console.log(y1, z, y2)
// if something similar were built into destructuring syntax,
// can you imagine how confusing it could get, and cause of all kinds of unexpected behavior?

How step through elements of an Array or properties of an Object for Recursion Functions

I apologize if this is a dumb question. I can't really find any resources via google that go through this topic. I don't understand how to step through an array of properties of an object in a recursion function since by definition a recursion will loop through itself. I know how to iterate through an array without a for loop in a recursion. What I don't understand is how to loop through an object for a Recursion. This is just some code I made up to demonstrate my lack of understanding.
var input1 = [1, 2, 3, 4, 5];
var input2 = {1: 'a', 2: 'b', 3: 'c'};
//for arrays
var arrayRecursion = function(someArray) {
var result = [];
//base case
if (someArray.length === 0) {
return result;
} else {
result.push(someArray.slice(0, 1));
return result.concat(arrayRecursion(someArray.slice(1)));
}
}
//for objects trying to copy input into results
var objectRecursion = function(someObject) {
var result = {};
for (var value in someObject) {
//base case
if (typeof(someObject[key]) !== 'object') {
return result;
}
//recursion
}
}
The main question I have is for my object recursion. If I have an established for - in loop for an object. How does it ever iterate through it? I don't have a recursion filled in because I have no clue how to approach this. If I call the recursion for the object, does it move onto the next property of the object? If so, how? Wouldn't you be starting the for - in loop all over again from the start? I guess where my logic lies is that the for loop is NOT continued from every recursion called because it executes the function which starts the loop from the first property
for..in loops iterate over properties, not values - (var value in someObject) will be quite misleading and result in bugs.
Once you have a reference to a value of the object, check whether it's an object or not. If it's an object, call the recursive objectRecursion and assign the result to the result object at the same property. (Don't return at this point, since that'll terminate the function)
Note that typeof is a keyword, not a function - don't put parentheses after it.
A related issue is that null's typeof is object too, so you'll have to compare against that as well.
var input2 = {1: 'a', 2: 'b', 3: 'c', foo: { prop: 2 }};
const objectRecursion = (someObject) => {
const result = {};
for (const [key, value] of Object.entries(someObject)) {
result[key] = typeof value === 'object' && value !== null
? objectRecursion(value)
: value;
}
return result;
};
console.log(objectRecursion(input2));
For a more flexible function which handles and copies arrays as well:
var input2 = {1: 'a', 2: 'b', 3: 'c', foo: { prop: 2, prop2: [3, 4, 5, { nested: 'nested' }] }};
const objectRecursion = (someItem) => {
if (typeof someItem !== 'object' && someItem !== null) {
return someItem;
}
if (Array.isArray(someItem)) {
return someItem.map(objectRecursion);
}
const result = {};
for (const [key, value] of Object.entries(someItem)) {
result[key] = objectRecursion(value)
}
return result;
};
console.log(objectRecursion(input2));
This should work recursively, using apply
https://jsfiddle.net/cz1frnL8/
var o = {1: 'a', 2: 'b', 3: 'c', foo: { prop: 2, prop2: [3, 4, 5, { nested: 'nested' }] }};
function process(key,value) {
console.log(key + " : "+value);
}
function traverse(o,func) {
for (var i in o) {
func.apply(this,[i,o[i]]);
if (o[i] !== null && typeof(o[i])=="object") {
traverse(o[i],func);
}
}
}
traverse(o,process);
My experience with using recursion with Objects has mainly been with recursing through nested objects rather than through sets of keys and values on the same object. I think this is because recursion as a pattern lends itself naturally to things that are fractal -- that is, where the data being operated on at each level of recursive depth is structurally similar.
Trees are a great example of this. Suppose I have a tree of node objects with the following structure:
4 - 8 - 9
| |
2 5 - 7
|
1
As a JS object, it might look like this.
{
val: 4,
left: {
val: 2,
left: {
val: 1
}
},
right: {
val: 8,
left: {
val: 5,
right: {
val: 7
}
},
right: {
val: 9
}
}
}
Notice how if I were to look at the object representing the left or right node from the root, it's structured the same as its parent? They're each effectively their own tree, but combined into a larger tree (this is what I mean by fractal).
If you wanted to find the largest value in this tree, you could do so by using recursion to iterate through the branches.
const getLargest = function (node) {
return Math.max(node.val, getLargest(node.left), getLargest(node.right));
};
That said, it's totally possible to use recursion on smaller and smaller sets of key-value pairs within an object. It might look something like this:
const exampleObject = {
a: 1,
b: 2,
c: 3
};
const recurse = function(obj) {
const keys = Object.keys(obj);
const firstKey = keys[0];
console.log(obj[firstKey]); // Or whatever; do a thing with the first key-value pair.
const smallerObj = Object.assign({}, obj); // Create a clone of the original; not necessary, but probably a good idea.
delete smallerObj[firstKey]; // Remove the key that we've just used.
recurse(smallerObj);
};
It's a little less natural in JS, but still totally doable. JavaScript object keys aren't sorted, but you could add a sort to const keys = Object.keys(obj) if you wanted to run through the keys in some specific order.

How to prevent automatic sort of Object numeric property?

Why I met this problem:
I tried to solve an algorithm problem and I need to return the number which appeared most of the times in an array. Like [5,4,3,2,1,1] should return 1.
And also when two number appear same time as the maximum appearance return the one came first. Like [5,5,2,2,1] return 5 because 5 appear first. I use an object to store the appearance of each number. The key is the number itself.
So When the input is [5,5,2,2,1] my object should be
Object {5: 2, 2: 2, 1: 1} but actually I got Object {1: 1, 2: 2, 5: 2}
So When I use for..in to iterate the object I got 2 returned instead of 5 . So that's why I asked this question.
This problem occurs in Chrome console and I'm not sure if this is a common issue:
When I run the following code
var a = {};
a[0]=1;
a[1]=2;
a[2]=3;
a is: Object {0: 1, 1: 2, 2: 3}
But when I reverse the order of assignment like:
var a = {};
a[2]=3;
a[1]=2;
a[0]=1;
a is also:Object {0: 1, 1: 2, 2: 3}
The numeric property automatic sorted in ascending order.
I tried prefix or postfix the numeric property like
var a = {};
a['p'+0]=1;
a['p'+1]=2;
a['p'+2]=3;
console.log(a);//Object {p0: 1, p1: 2, p2: 3}
And this keep the property order. Is this the best way to solve the problem? And is there anyway to prevent this auto sort behavior? Is this only happen in Chrome V8 JavaScript engine? Thank you in advance!
target = {}
target[' ' + key] = value // numeric key
This can prevent automatic sort of Object numeric property.
You really can't rely on order of an object fields in JavaScript, but I can suggest to use Map (ES6/ES2015 standard) if you need to preserve order of your key, value pair object. See the snippet below:
let myObject = new Map();
myObject.set('z', 33);
myObject.set('1', 100);
myObject.set('b', 3);
for (let [key, value] of myObject) {
console.log(key, value);
}
// z 33
// 1 100
// b 3
You are using a JS object, that by definition does not keep order. Think of it as a key => value map.
You should be using an array, that will keep whatever you insert on the index you inserted it into. Think of it as a list.
Also notice that you did not in fact "reverse the order of the assignment", because you inserted elements on the same index every time.
This is an old topic but it is still worth mentioning as it is hard to find a straight explanation in one-minute googling.
I recently had a coding exercise that finding the first occurrence of the least/most frequent integer in an array, it is pretty much the same as your case.
I encountered the same problem as you, having the numeric keys sorted by ASC in JavaScript object, which is not preserving the original order of elements, which is the default behavior in js.
A better way to solve this in ES6 is to use a new data type called: Map
Map can preserve the original order of elements(pairs), and also have the unique key benefit from object.
let map = new Map()
map.set(4, "first") // Map(1) {4 => "first"}
map.set(1, "second") // Map(2) {4 => "first", 1 => "second"}
map.set(2, "third") // Map(3) {4 => "first", 1 => "second", 2 => "third"}
for(let [key, value] of map) {
console.log(key, value)
}
// 4 "first"
// 1 "second"
// 2 "third"
However, using the object data type can also solve the problem, but we need the help of the input array to get back the original order of elements:
function findMostAndLeast(arr) {
let countsMap = {};
let mostFreq = 0;
let leastFreq = arr.length;
let mostFreqEl, leastFreqEl;
for (let i = 0; i < arr.length; i++) {
let el = arr[i];
// Count each occurrence
if (countsMap[el] === undefined) {
countsMap[el] = 1;
} else {
countsMap[el] += 1;
}
}
// Since the object is sorted by keys by default in JS, have to loop again the original array
for (let i = 0; i < arr.length; i++) {
const el = arr[i];
// find the least frequent
if (leastFreq > countsMap[el]) {
leastFreqEl = Number(el);
leastFreq = countsMap[el];
}
// find the most frequent
if (countsMap[el] > mostFreq) {
mostFreqEl = Number(el);
mostFreq = countsMap[el];
}
}
return {
most_frequent: mostFreqEl,
least_frequent: leastFreqEl
}
}
const testData = [6, 1, 3, 2, 4, 7, 8, 9, 10, 4, 4, 4, 10, 1, 1, 1, 1, 6, 6, 6, 6];
console.log(findMostAndLeast(testData)); // { most_frequent: 6, least_frequent: 3 }, it gets 6, 3 instead of 1, 2
To prevent the automatic sort of numeric keys of Object in Javascript, the best way is to tweak the Object keys a little bit.
We can insert an "e" in front of every key name to avoid lexicographical sorting of keys and to get the proper output slice the "e", by using the following code;
object_1 = {
"3": 11,
"2": 12,
"1": 13
}
let automaticSortedKeys = Object.keys(object_1);
console.log(automaticSortedKeys) //["1", "2", "3"]
object_2 = {
"e3": 11,
"e2": 12,
"e1": 13
}
let rawObjectKeys = Object.keys(object_2);
console.log(rawObjectKeys) //["e3", "e2", "e1"]
let properKeys = rawObjectKeys.map(function(element){
return element.slice(1)
});
console.log(properKeys) //["3", "2", "1"]
instead of generating an object like {5: 2, 2: 2, 1: 1}
generate an array to the effect of
[
{key: 5, val: 2},
{key: 2, val: 2},
{key: 1, val: 1}
]
or... keep track of the sort order in a separate value or key
I've stumbled with this issue with our normalised array which keyed with Ids> After did my research, I found out there's no way to fix using the object keys because by default the Javascript is sorting any object key with number when you iterate it.
The solution I've done and it worked for me is to put a 'sortIndex' field and used that to sort the list.
The simplest and the best way to preserve the order of the keys in the array obtained by Object.keys() is to manipulate the Object keys a little bit.
insert a "_" in front of every key name. then run the following code!
myObject = {
_a: 1,
_1: 2,
_2: 3
}
const myObjectRawKeysArray = Object.keys(myObject);
console.log(myObjectRawKeysArray)
//["_a", "_1", "_2"]
const myDesiredKeysArray = myObjectRawKeysArray.map(rawKey => {return rawKey.slice(1)});
console.log(myDesiredKeysArray)
//["a", "1", "2"]
You get the desired order in the array with just a few lines of code. hApPy CoDiNg :)
I came across this same problem, and after search a lot about that, i found out that the solution to prevent this behavior is make key as string.
Like that:
{"a": 2, "b": 2}
you can use Map() in javascript ES6 which will keep the order of the keys insertion.
just trying to solve your problem in an alternative solution, recently like to practise leetcode-like question
function solution(arr) {
const obj = {};
const record = {
value: null,
count: 0
};
for (let i = 0; i < arr.length; i++) {
let current = arr[i];
if (!obj[current]) {
obj[current] = 0;
}
obj[current]++;
if (obj[current] > record.count) {
record.value = current;
record.count = obj[current];
}
}
console.log("mode number: ", record.value);
console.log("mode number count: ", record.count);
}
simply do that while you're working with a numeric array index
data = {}
data[key] = value

How to insert an item into an array at a specific index (JavaScript)

I am looking for a JavaScript array insert method, in the style of:
arr.insert(index, item)
Preferably in jQuery, but any JavaScript implementation will do at this point.
You want the splice function on the native array object.
arr.splice(index, 0, item); will insert item into arr at the specified index (deleting 0 items first, that is, it's just an insert).
In this example we will create an array and add an element to it into index 2:
var arr = [];
arr[0] = "Jani";
arr[1] = "Hege";
arr[2] = "Stale";
arr[3] = "Kai Jim";
arr[4] = "Borge";
console.log(arr.join()); // Jani,Hege,Stale,Kai Jim,Borge
arr.splice(2, 0, "Lene");
console.log(arr.join()); // Jani,Hege,Lene,Stale,Kai Jim,Borge
You can implement the Array.insert method by doing this:
Array.prototype.insert = function ( index, ...items ) {
this.splice( index, 0, ...items );
};
Then you can use it like:
var arr = [ 'A', 'B', 'E' ];
arr.insert(2, 'C', 'D');
// => arr == [ 'A', 'B', 'C', 'D', 'E' ]
Other than splice, you can use this approach which will not mutate the original array, but it will create a new array with the added item. It is useful, when you need to avoid mutation. I'm using the ES6 spread operator here.
const items = [1, 2, 3, 4, 5]
const insert = (arr, index, newItem) => [
// part of the array before the specified index
...arr.slice(0, index),
// inserted item
newItem,
// part of the array after the specified index
...arr.slice(index)
]
const result = insert(items, 1, 10)
console.log(result)
// [1, 10, 2, 3, 4, 5]
This can be used to add more than one item by tweaking the function a bit to use the rest operator for the new items, and spread that in the returned result as well:
const items = [1, 2, 3, 4, 5]
const insert = (arr, index, ...newItems) => [
// part of the array before the specified index
...arr.slice(0, index),
// inserted items
...newItems,
// part of the array after the specified index
...arr.slice(index)
]
const result = insert(items, 1, 10, 20)
console.log(result)
// [1, 10, 20, 2, 3, 4, 5]
Custom array insert methods
1. With multiple arguments and chaining support
/* Syntax:
array.insert(index, value1, value2, ..., valueN) */
Array.prototype.insert = function(index) {
this.splice.apply(this, [index, 0].concat(
Array.prototype.slice.call(arguments, 1)));
return this;
};
It can insert multiple elements (as native splice does) and supports chaining:
["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(1, 6);
// ["b", "X", "Y", "Z", "c"]
2. With array-type arguments merging and chaining support
/* Syntax:
array.insert(index, value1, value2, ..., valueN) */
Array.prototype.insert = function(index) {
index = Math.min(index, this.length);
arguments.length > 1
&& this.splice.apply(this, [index, 0].concat([].pop.call(arguments)))
&& this.insert.apply(this, arguments);
return this;
};
It can merge arrays from the arguments with the given array and also supports chaining:
["a", "b", "c", "d"].insert(2, "V", ["W", "X", "Y"], "Z").join("-");
// "a-b-V-W-X-Y-Z-c-d"
DEMO: http://jsfiddle.net/UPphH/
Using Array.prototype.splice() is an easy way to achieve it
const numbers = ['one', 'two', 'four', 'five']
numbers.splice(2, 0, 'three');
console.log(numbers)
Read more about Array.prototype.splice
If you want to insert multiple elements into an array at once check out this Stack Overflow answer: A better way to splice an array into an array in javascript
Also here are some functions to illustrate both examples:
function insertAt(array, index) {
var arrayToInsert = Array.prototype.splice.apply(arguments, [2]);
return insertArrayAt(array, index, arrayToInsert);
}
function insertArrayAt(array, index, arrayToInsert) {
Array.prototype.splice.apply(array, [index, 0].concat(arrayToInsert));
return array;
}
Finally here is a jsFiddle so you can see it for yourself: http://jsfiddle.net/luisperezphd/Wc8aS/
And this is how you use the functions:
// if you want to insert specific values whether constants or variables:
insertAt(arr, 1, "x", "y", "z");
// OR if you have an array:
var arrToInsert = ["x", "y", "z"];
insertArrayAt(arr, 1, arrToInsert);
Solutions & Performance
Today (2020.04.24) I perform tests for chosen solutions for big and small arrays. I tested them on macOS v10.13.6 (High Sierra) on Chrome 81.0, Safari 13.1, and Firefox 75.0.
Conclusions
For all browsers
surprisingly for small arrays, non-in-place solutions based on slice and reduce (D,E,F) are usually 10x-100x faster than in-place solutions
for big arrays the in-place-solutions based on splice (AI, BI, and CI) was fastest (sometimes ~100x - but it depends on the array size)
for small arrays the BI solution was slowest
for big arrays the E solution was slowest
Details
Tests were divided into two groups: in-place solutions (AI, BI, and CI) and non-in-place solutions (D, E, and F) and was performed for two cases:
test for an array with 10 elements - you can run it here
test for an array with 1,000,000 elements - you can run it here
Tested code is presented in the below snippet:
jsfiddle
function AI(arr, i, el) {
arr.splice(i, 0, el);
return arr;
}
function BI(arr, i, el) {
Array.prototype.splice.apply(arr, [i, 0, el]);
return arr;
}
function CI(arr, i, el) {
Array.prototype.splice.call(arr, i, 0, el);
return arr;
}
function D(arr, i, el) {
return arr.slice(0, i).concat(el, arr.slice(i));
}
function E(arr, i, el) {
return [...arr.slice(0, i), el, ...arr.slice(i)]
}
function F(arr, i, el) {
return arr.reduce((s, a, j)=> (j-i ? s.push(a) : s.push(el, a), s), []);
}
// -------------
// TEST
// -------------
let arr = ["a", "b", "c", "d", "e", "f"];
let log = (n, f) => {
let a = f([...arr], 3, "NEW");
console.log(`${n}: [${a}]`);
};
log('AI', AI);
log('BI', BI);
log('CI', CI);
log('D', D);
log('E', E);
log('F', F);
This snippet only presents tested code (it not perform tests)
Example results for a small array on Google Chrome are below:
For proper functional programming and chaining purposes, an invention of Array.prototype.insert() is essential. Actually, the splice could have been perfect if it had returned the mutated array instead of a totally meaningless empty array. So here it goes:
Array.prototype.insert = function(i,...rest){
this.splice(i,0,...rest)
return this
}
var a = [3,4,8,9];
document.write("<pre>" + JSON.stringify(a.insert(2,5,6,7)) + "</pre>");
Well, OK, the above with the Array.prototype.splice() one mutates the original array and some might complain like "you shouldn't modify what doesn't belong to you" and that might turn out to be right as well. So for the public welfare, I would like to give another Array.prototype.insert() which doesn't mutate the original array. Here it goes;
Array.prototype.insert = function(i,...rest){
return this.slice(0,i).concat(rest,this.slice(i));
}
var a = [3,4,8,9],
b = a.insert(2,5,6,7);
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));
You can use splice() for this
The splice() method usually receives three arguments when adding an element:
The index of the array where the item is going to be added.
The number of items to be removed, which in this case is 0.
The element to add.
let array = ['item 1', 'item 2', 'item 3']
let insertAtIndex = 0
let itemsToRemove = 0
array.splice(insertAtIndex, itemsToRemove, 'insert this string on index 0')
console.log(array)
I recommend using pure JavaScript in this case. Also there isn't any insert method in JavaScript, but we have a method which is a built-in Array method which does the job for you. It's called splice...
Let's see what's splice()...
The splice() method changes the contents of an array by removing
existing elements and/or adding new elements.
OK, imagine we have this array below:
const arr = [1, 2, 3, 4, 5];
We can remove 3 like this:
arr.splice(arr.indexOf(3), 1);
It will return 3, but if we check the arr now, we have:
[1, 2, 4, 5]
So far, so good, but how we can add a new element to array using splice?
Let's put back 3 in the arr...
arr.splice(2, 0, 3);
Let's see what we have done...
We use splice again, but this time for the second argument, we pass 0, meaning we don't want to delete any item, but at the same time, we add a third argument which is the 3 that will be added at second index...
You should be aware that we can delete and add at the same time. For example, now we can do:
arr.splice(2, 2, 3);
Which will delete two items at index 2. Then add 3 at index 2 and the result will be:
[1, 2, 3, 5];
This is showing how each item in splice work:
array.splice(start, deleteCount, item1, item2, item3 ...)
Here are two ways:
const array = [ 'My', 'name', 'Hamza' ];
array.splice(2, 0, 'is');
console.log("Method 1: ", array.join(" "));
Or
Array.prototype.insert = function ( index, item ) {
this.splice( index, 0, item );
};
const array = [ 'My', 'name', 'Hamza' ];
array.insert(2, 'is');
console.log("Method 2 : ", array.join(" "));
Append a single element at a specific index
// Append at a specific position (here at index 1)
arrName.splice(1, 0,'newName1');
// 1: index number, 0: number of element to remove, newName1: new element
// Append at a specific position (here at index 3)
arrName[3] = 'newName1';
Append multiple elements at a specific index
// Append from index number 1
arrName.splice(1, 0, 'newElemenet1', 'newElemenet2', 'newElemenet3');
// 1: index number from where append start,
// 0: number of element to remove,
//newElemenet1,2,3: new elements
Array#splice() is the way to go, unless you really want to avoid mutating the array. Given 2 arrays arr1 and arr2, here's how you would insert the contents of arr2 into arr1 after the first element:
const arr1 = ['a', 'd', 'e'];
const arr2 = ['b', 'c'];
arr1.splice(1, 0, ...arr2); // arr1 now contains ['a', 'b', 'c', 'd', 'e']
console.log(arr1)
If you are concerned about mutating the array (for example, if using Immutable.js), you can instead use slice(), not to be confused with splice() with a 'p'.
const arr3 = [...arr1.slice(0, 1), ...arr2, ...arr1.slice(1)];
Another possible solution, with usage of Array.reduce.
const arr = ["apple", "orange", "raspberry"];
const arr2 = [1, 2, 4];
const insert = (arr, item, index) =>
arr.reduce(function(s, a, i) {
i === index ? s.push(item, a) : s.push(a);
return s;
}, []);
console.log(insert(arr, "banana", 1));
console.log(insert(arr2, 3, 2))
Even though this has been answered already, I'm adding this note for an alternative approach.
I wanted to place a known number of items into an array, into specific positions, as they come off of an "associative array" (i.e. an object) which by definition is not guaranteed to be in a sorted order. I wanted the resulting array to be an array of objects, but the objects to be in a specific order in the array since an array guarantees their order. So I did this.
First the source object, a JSONB string retrieved from PostgreSQL. I wanted to have it sorted by the "order" property in each child object.
var jsonb_str = '{"one": {"abbr": "", "order": 3}, "two": {"abbr": "", "order": 4}, "three": {"abbr": "", "order": 5}, "initialize": {"abbr": "init", "order": 1}, "start": {"abbr": "", "order": 2}}';
var jsonb_obj = JSON.parse(jsonb_str);
Since the number of nodes in the object is known, I first create an array with the specified length:
var obj_length = Object.keys(jsonb_obj).length;
var sorted_array = new Array(obj_length);
And then iterate the object, placing the newly created temporary objects into the desired locations in the array without really any "sorting" taking place.
for (var key of Object.keys(jsonb_obj)) {
var tobj = {};
tobj[key] = jsonb_obj[key].abbr;
var position = jsonb_obj[key].order - 1;
sorted_array[position] = tobj;
}
console.dir(sorted_array);
Immutable insertion
Using the splice method is surely the best answer if you need to insert into an array in-place.
However, if you are looking for an immutable function that returns a new updated array instead of mutating the original array on insert, you can use the following function.
function insert(array, index) {
const items = Array.prototype.slice.call(arguments, 2);
return [].concat(array.slice(0, index), items, array.slice(index));
}
const list = ['one', 'two', 'three'];
const list1 = insert(list, 0, 'zero'); // Insert single item
const list2 = insert(list, 3, 'four', 'five', 'six'); // Insert multiple
console.log('Original list: ', list);
console.log('Inserted list1: ', list1);
console.log('Inserted list2: ', list2);
Note: This is a pre-ES6 way of doing it, so it works for both older and newer browsers.
If you're using ES6 then you can try out rest parameters too; see this answer.
Anyone who's still having issues with this one and have tried all the options in previous answers and never got it. I'm sharing my solution, and this is to take into consideration that you don't want to explicitly state the properties of your object vs the array.
function isIdentical(left, right){
return JSON.stringify(left) === JSON.stringify(right);
}
function contains(array, obj){
let count = 0;
array.map((cur) => {
if(this.isIdentical(cur, obj))
count++;
});
return count > 0;
}
This is a combination of iterating the reference array and comparing it to the object you wanted to check, converting both of them into a string, and then iterating if it matched. Then you can just count. This can be improved, but this is where I settled.
Taking profit of the reduce method as follows:
function insert(arr, val, index) {
return index >= arr.length
? arr.concat(val)
: arr.reduce((prev, x, i) => prev.concat(i === index ? [val, x] : x), []);
}
So in this way we can return a new array (will be a cool functional way - more much better than using push or splice) with the element inserted at index, and if the index is greater than the length of the array it will be inserted at the end.
I tried this and it is working fine!
var initialArr = ["India","China","Japan","USA"];
initialArr.splice(index, 0, item);
Index is the position where you want to insert or delete the element.
0, i.e., the second parameter, defines the number of elements from the index to be removed.
item contains the new entries which you want to make in the array. It can be one or more than one.
initialArr.splice(2, 0, "Nigeria");
initialArr.splice(2, 0, "Australia","UK");
I have to agree with Redu's answer because splice() definitely has a bit of a confusing interface. And the response given by cdbajorin that "it only returns an empty array when the second parameter is 0. If it's greater than 0, it returns the items removed from the array" is, while accurate, proving the point.
The function's intent is to splice or as said earlier by Jakob Keller, "to join or connect, also to change.
You have an established array that you are now changing which would involve adding or removing elements...." Given that, the return value of the elements, if any, that were removed is awkward at best. And I 100% agree that this method could have been better suited to chaining if it had returned what seems natural, a new array with the spliced elements added. Then you could do things like ["19", "17"].splice(1,0,"18").join("...") or whatever you like with the returned array.
The fact that it returns what was removed is just kind of nonsense IMHO. If the intention of the method was to "cut out a set of elements" and that was its only intent, maybe. It seems like if I don't know what I'm cutting out already though, I probably have little reason to cut those elements out, doesn't it?
It would be better if it behaved like concat(), map(), reduce(), slice(), etc. where a new array is made from the existing array rather than mutating the existing array. Those are all chainable, and that is a significant issue. It's rather common to chain array manipulation.
It seems like the language needs to go one or the other direction and try to stick to it as much as possible. JavaScript being functional and less declarative, it just seems like a strange deviation from the norm.
I like a little safety and I use this:
Array.prototype.Insert = function (item, before) {
if (!item) return;
if (before == null || before < 0 || before > this.length - 1) {
this.push(item);
return;
}
this.splice(before, 0, item);
}
var t = ["a", "b"]
t.Insert("v", 1)
console.log(t)
You can do it with array.splice:
/**
* #param arr: Array
* #param item: item to insert
* #param index: index at which to insert
* #returns array with the inserted element
*/
export function _arrayInsertAt<T>(arr: T[], item: T, index: number) {
return arr.splice(index, 0, item);;
}
Doc of array.slice
Here's a working function that I use in one of my applications.
This checks if an item exists:
let ifExist = (item, strings = [ '' ], position = 0) => {
// Output into an array with an empty string. Important just in case their isn't any item.
let output = [ '' ];
// Check to see if the item that will be positioned exist.
if (item) {
// Output should be equal to an array of strings.
output = strings;
// Use splice() in order to break the array.
// Use positional parameters to state where to put the item
// and 0 is to not replace an index. Item is the actual item we are placing at the prescribed position.
output.splice(position, 0, item);
}
// Empty string is so we do not concatenate with comma or anything else.
return output.join("");
};
And then I call it below.
ifExist("friends", [ ' ( ', ' )' ], 1)} // Output: ( friends )
ifExist("friends", [ ' - '], 1)} // Output: - friends
ifExist("friends", [ ':'], 0)} // Output: friends:
Here is the modern (Typescript functional) way:
export const insertItemInList = <T>(
arr: T[],
index: number,
newItem: T
): T[] => [...arr.slice(0, index), newItem, ...arr.slice(index)]
I do it like so:
const insert = (what, where, index) =>
([...where.slice(0, index), what , ...where.slice(index, where.length)]);
const insert = (what, where, index) =>
([...where.slice(0, index), what , ...where.slice(index, where.length)]);
const list = [1, 2, 3, 4, 5, 6];
const newList = insert('a', list, 2);
console.log(newList.indexOf('a') === 2);
Here's a simple function that supports inserting multiple values at the same time:
function add_items_to_array_at_position(array, index, new_items)
{
return [...array.slice(0, index), ...new_items, ...array.slice(index)];
}
Usage example:
let old_array = [1,2,5];
let new_array = add_items_to_array_at_position(old_array, 2, [3,4]);
console.log(new_array);
//Output: [1,2,3,4,5]
var array= [10,20,30,40]
var i;
var pos=2; //pos=index + 1
/*pos is position which we want to insert at which is index + 1.position two in an array is index 1.*/
var value=5
//value to insert
//Initialize from last array element
for(i=array.length-1;i>=pos-1;i--){
array[i+1]=array[i]
}
array[pos-1]=value
console.log(array)
Multi purpose for ARRAY and ARRAY OF OBJECT reusable approach
let arr = [0,1,2];
let obj = [{ name: "abc"},{ name: "xyz"},{ name: "ijk"} ];
const addArrayItemAtIndex = ( array, index, newItem ) => {
return [...array.slice(0, index), newItem, ...array.slice(index)];
}
// For Array
console.log( addArrayItemAtIndex(arr, 2, 159 ) );
// For Array of Objects
console.log( addArrayItemAtIndex(obj, 0, { name: "AMOOS"} ) );

Categories