How to prevent automatic sort of Object numeric property? - javascript

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

Related

what is the shortest way to remove duplicate data/entries from an Array in Javascipt? [duplicate]

I have an array of numbers that I need to make sure are unique. I found the code snippet below on the internet and it works great until the array has a zero in it. I found this other script here on Stack Overflow that looks almost exactly like it, but it doesn't fail.
So for the sake of helping me learn, can someone help me determine where the prototype script is going wrong?
Array.prototype.getUnique = function() {
var o = {}, a = [], i, e;
for (i = 0; e = this[i]; i++) {o[e] = 1};
for (e in o) {a.push (e)};
return a;
}
More answers from duplicate question:
Remove duplicate values from JS array
Similar question:
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
With JavaScript 1.6 / ECMAScript 5 you can use the native filter method of an Array in the following way to get an array with unique values:
function onlyUnique(value, index, array) {
return self.indexOf(value) === index;
}
// usage example:
var a = ['a', 1, 'a', 2, '1'];
var unique = a.filter(onlyUnique);
console.log(unique); // ['a', 1, 2, '1']
The native method filter will loop through the array and leave only those entries that pass the given callback function onlyUnique.
onlyUnique checks, if the given value is the first occurring. If not, it must be a duplicate and will not be copied.
This solution works without any extra library like jQuery or prototype.js.
It works for arrays with mixed value types too.
For old Browsers (<ie9), that do not support the native methods filter and indexOf you can find work arounds in the MDN documentation for filter and indexOf.
If you want to keep the last occurrence of a value, simply replace indexOf with lastIndexOf.
With ES6 this can be shorten to:
// usage example:
var myArray = ['a', 1, 'a', 2, '1'];
var unique = myArray.filter((value, index, array) => array.indexOf(value) === index);
console.log(unique); // unique is ['a', 1, 2, '1']
Thanks to Camilo Martin for hint in comment.
ES6 has a native object Set to store unique values. To get an array with unique values you could now do this:
var myArray = ['a', 1, 'a', 2, '1'];
let unique = [...new Set(myArray)];
console.log(unique); // unique is ['a', 1, 2, '1']
The constructor of Set takes an iterable object, like an Array, and the spread operator ... transform the set back into an Array. Thanks to Lukas Liese for hint in comment.
Updated answer for ES6/ES2015: Using the Set and the spread operator (thanks le-m), the single line solution is:
let uniqueItems = [...new Set(items)]
Which returns
[4, 5, 6, 3, 2, 23, 1]
I split all answers to 4 possible solutions:
Use object { } to prevent duplicates
Use helper array [ ]
Use filter + indexOf
Bonus! ES6 Sets method.
Here's sample codes found in answers:
Use object { } to prevent duplicates
function uniqueArray1( ar ) {
var j = {};
ar.forEach( function(v) {
j[v+ '::' + typeof v] = v;
});
return Object.keys(j).map(function(v){
return j[v];
});
}
Use helper array [ ]
function uniqueArray2(arr) {
var a = [];
for (var i=0, l=arr.length; i<l; i++)
if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
a.push(arr[i]);
return a;
}
Use filter + indexOf
function uniqueArray3(a) {
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
// usage
var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']
return unique;
}
Use ES6 [...new Set(a)]
function uniqueArray4(a) {
return [...new Set(a)];
}
And I wondered which one is faster. I've made sample Google Sheet to test functions. Note: ECMA 6 is not avaliable in Google Sheets, so I can't test it.
Here's the result of tests:
I expected to see that code using object { } will win because it uses hash. So I'm glad that tests showed the best results for this algorithm in Chrome and IE. Thanks to #rab for the code.
Update 2020
Google Script enabled ES6 Engine. Now I tested the last code with Sets and it appeared faster than the object method.
You can also use underscore.js.
console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="http://underscorejs.org/underscore-min.js"></script>
which will return:
[1, 2, 3, 4]
One Liner, Pure JavaScript
With ES6 syntax
list = list.filter((x, i, a) => a.indexOf(x) == i)
x --> item in array
i --> index of item
a --> array reference, (in this case "list")
With ES5 syntax
list = list.filter(function (x, i, a) {
return a.indexOf(x) == i;
});
Browser Compatibility: IE9+
Remove duplicates using Set.
Array with duplicates
const withDuplicates = [2, 2, 5, 5, 1, 1, 2, 2, 3, 3];
Get a new array without duplicates by using Set
const withoutDuplicates = Array.from(new Set(withDuplicates));
A shorter version
const withoutDuplicates = [...new Set(withDuplicates)];
Result: [2, 5, 1, 3]
Many of the answers here may not be useful to beginners. If de-duping an array is difficult, will they really know about the prototype chain, or even jQuery?
In modern browsers, a clean and simple solution is to store data in a Set, which is designed to be a list of unique values.
const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
const uniqueCars = Array.from(new Set(cars));
console.log(uniqueCars);
The Array.from is useful to convert the Set back to an Array so that you have easy access to all of the awesome methods (features) that arrays have. There are also other ways of doing the same thing. But you may not need Array.from at all, as Sets have plenty of useful features like forEach.
If you need to support old Internet Explorer, and thus cannot use Set, then a simple technique is to copy items over to a new array while checking beforehand if they are already in the new array.
// Create a list of cars, with duplicates.
var cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
// Create a list of unique cars, to put a car in if we haven't already.
var uniqueCars = [];
// Go through each car, one at a time.
cars.forEach(function (car) {
// The code within the following block runs only if the
// current car does NOT exist in the uniqueCars list
// - a.k.a. prevent duplicates
if (uniqueCars.indexOf(car) === -1) {
// Since we now know we haven't seen this car before,
// copy it to the end of the uniqueCars list.
uniqueCars.push(car);
}
});
To make this instantly reusable, let's put it in a function.
function deduplicate(data) {
if (data.length > 0) {
var result = [];
data.forEach(function (elem) {
if (result.indexOf(elem) === -1) {
result.push(elem);
}
});
return result;
}
}
So to get rid of the duplicates, we would now do this.
var uniqueCars = deduplicate(cars);
The deduplicate(cars) part becomes the thing we named result when the function completes.
Just pass it the name of any array you like.
Using ES6 new Set
var array = [3,7,5,3,2,5,2,7];
var unique_array = [...new Set(array)];
console.log(unique_array); // output = [3,7,5,2]
Using For Loop
var array = [3,7,5,3,2,5,2,7];
for(var i=0;i<array.length;i++) {
for(var j=i+1;j<array.length;j++) {
if(array[i]===array[j]) {
array.splice(j,1);
}
}
}
console.log(array); // output = [3,7,5,2]
I have since found a nice method that uses jQuery
arr = $.grep(arr, function(v, k){
return $.inArray(v ,arr) === k;
});
Note: This code was pulled from Paul Irish's duck punching post - I forgot to give credit :P
Magic
a.filter(e=>!(t[e]=e in t))
O(n) performance - we assume your array is in a and t={}. Explanation here (+Jeppe impr.)
let unique = (a,t={}) => a.filter(e=>!(t[e]=e in t));
// "stand-alone" version working with global t:
// a1.filter((t={},e=>!(t[e]=e in t)));
// Test data
let a1 = [5,6,0,4,9,2,3,5,0,3,4,1,5,4,9];
let a2 = [[2, 17], [2, 17], [2, 17], [1, 12], [5, 9], [1, 12], [6, 2], [1, 12]];
let a3 = ['Mike', 'Adam','Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'];
// Results
console.log(JSON.stringify( unique(a1) ))
console.log(JSON.stringify( unique(a2) ))
console.log(JSON.stringify( unique(a3) ))
The simplest, and fastest (in Chrome) way of doing this:
Array.prototype.unique = function() {
var a = [];
for (var i=0, l=this.length; i<l; i++)
if (a.indexOf(this[i]) === -1)
a.push(this[i]);
return a;
}
Simply goes through every item in the array, tests if that item is already in the list, and if it's not, pushes to the array that gets returned.
According to JSBench, this function is the fastest of the ones I could find anywhere - feel free to add your own though.
The non-prototype version:
function uniques(arr) {
var a = [];
for (var i=0, l=arr.length; i<l; i++)
if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
a.push(arr[i]);
return a;
}
Sorting
When also needing to sort the array, the following is the fastest:
Array.prototype.sortUnique = function() {
this.sort();
var last_i;
for (var i=0;i<this.length;i++)
if ((last_i = this.lastIndexOf(this[i])) !== i)
this.splice(i+1, last_i-i);
return this;
}
or non-prototype:
function sortUnique(arr) {
arr.sort();
var last_i;
for (var i=0;i<arr.length;i++)
if ((last_i = arr.lastIndexOf(arr[i])) !== i)
arr.splice(i+1, last_i-i);
return arr;
}
This is also faster than the above method in most non-Chrome browsers.
We can do this using ES6 sets:
var duplicatesArray = [1, 2, 3, 4, 5, 1, 1, 1, 2, 3, 4];
var uniqueArray = [...new Set(duplicatesArray)];
console.log(uniqueArray); // [1,2,3,4,5]
["Defects", "Total", "Days", "City", "Defects"].reduce(function(prev, cur) {
return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
}, []);
[0,1,2,0,3,2,1,5].reduce(function(prev, cur) {
return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
}, []);
After looking into all the 90+ answers here, I saw there is room for one more:
Array.includes has a very handy second-parameter: "fromIndex", so by using it, every iteration of the filter callback method will search the array, starting from [current index] + 1 which guarantees not to include currently filtered item in the lookup and also saves time.
Note - this solution does not retain the order, as it removed duplicated items from left to right, but it wins the Set trick if the Array is a collection of Objects.
// 🚩 🚩 🚩
var list = [0,1,2,2,3,'a','b',4,5,2,'a']
console.log(
list.filter((v,i) => !list.includes(v,i+1))
)
// [0,1,3,"b",4,5,2,"a"]
Explanation:
For example, lets assume the filter function is currently iterating at index 2) and the value at that index happens to be 2. The section of the array that is then scanned for duplicates (includes method) is everything after index 2 (i+1):
👇 👇
[0, 1, 2, 2 ,3 ,'a', 'b', 4, 5, 2, 'a']
👆 |---------------------------|
And since the currently filtered item's value 2 is included in the rest of the array, it will be filtered out, because of the leading exclamation mark which negates the filter rule.
If order is important, use this method:
// 🚩 🚩 🚩
var list = [0,1,2,2,3,'a','b',4,5,2,'a']
console.log(
// Initialize with empty array and fill with non-duplicates
list.reduce((acc, v) => (!acc.includes(v) && acc.push(v), acc), [])
)
// [0,1,2,3,"a","b",4,5]
This has been answered a lot, but it didn't address my particular need.
Many answers are like this:
a.filter((item, pos, self) => self.indexOf(item) === pos);
But this doesn't work for arrays of complex objects.
Say we have an array like this:
const a = [
{ age: 4, name: 'fluffy' },
{ age: 5, name: 'spot' },
{ age: 2, name: 'fluffy' },
{ age: 3, name: 'toby' },
];
If we want the objects with unique names, we should use array.prototype.findIndex instead of array.prototype.indexOf:
a.filter((item, pos, self) => self.findIndex(v => v.name === item.name) === pos);
This prototype getUnique is not totally correct, because if i have a Array like: ["1",1,2,3,4,1,"foo"] it will return ["1","2","3","4"] and "1" is string and 1 is a integer; they are different.
Here is a correct solution:
Array.prototype.unique = function(a){
return function(){ return this.filter(a) }
}(function(a,b,c){ return c.indexOf(a,b+1) < 0 });
using:
var foo;
foo = ["1",1,2,3,4,1,"foo"];
foo.unique();
The above will produce ["1",2,3,4,1,"foo"].
You can simlply use the built-in functions Array.prototype.filter() and Array.prototype.indexOf()
array.filter((x, y) => array.indexOf(x) == y)
var arr = [1, 2, 3, 3, 4, 5, 5, 5, 6, 7, 8, 9, 6, 9];
var newarr = arr.filter((x, y) => arr.indexOf(x) == y);
console.log(newarr);
[...new Set(duplicates)]
This is the simplest one and referenced from MDN Web Docs.
const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)]) // [2, 3, 4, 5, 6, 7, 32]
Array.prototype.getUnique = function() {
var o = {}, a = []
for (var i = 0; i < this.length; i++) o[this[i]] = 1
for (var e in o) a.push(e)
return a
}
Without extending Array.prototype (it is said to be a bad practice) or using jquery/underscore, you can simply filter the array.
By keeping last occurrence:
function arrayLastUnique(array) {
return array.filter(function (a, b, c) {
// keeps last occurrence
return c.indexOf(a, b + 1) < 0;
});
},
or first occurrence:
function arrayFirstUnique(array) {
return array.filter(function (a, b, c) {
// keeps first occurrence
return c.indexOf(a) === b;
});
},
Well, it's only javascript ECMAScript 5+, which means only IE9+, but it's nice for a development in native HTML/JS (Windows Store App, Firefox OS, Sencha, Phonegap, Titanium, ...).
That's because 0 is a falsy value in JavaScript.
this[i] will be falsy if the value of the array is 0 or any other falsy value.
Now using sets you can remove duplicates and convert them back to the array.
var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];
console.log([...new Set(names)])
Another solution is to use sort & filter
var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];
var namesSorted = names.sort();
const result = namesSorted.filter((e, i) => namesSorted[i] != namesSorted[i+1]);
console.log(result);
If you're using Prototype framework there is no need to do 'for' loops, you can use http://prototypejs.org/doc/latest/language/Array/prototype/uniq/ like this:
var a = Array.uniq();
Which will produce a duplicate array with no duplicates. I came across your question searching a method to count distinct array records so after uniq() I used size() and there was my simple result.
p.s. Sorry if i mistyped something
edit: if you want to escape undefined records you may want to add compact() before, like this:
var a = Array.compact().uniq();
I had a slightly different problem where I needed to remove objects with duplicate id properties from an array. this worked.
let objArr = [{
id: '123'
}, {
id: '123'
}, {
id: '456'
}];
objArr = objArr.reduce((acc, cur) => [
...acc.filter((obj) => obj.id !== cur.id), cur
], []);
console.log(objArr);
If you're okay with extra dependencies, or you already have one of the libraries in your codebase, you can remove duplicates from an array in place using LoDash (or Underscore).
Usage
If you don't have it in your codebase already, install it using npm:
npm install lodash
Then use it as follows:
import _ from 'lodash';
let idArray = _.uniq ([
1,
2,
3,
3,
3
]);
console.dir(idArray);
Out:
[ 1, 2, 3 ]
I'm not sure why Gabriel Silveira wrote the function that way but a simpler form that works for me just as well and without the minification is:
Array.prototype.unique = function() {
return this.filter(function(value, index, array) {
return array.indexOf(value, index + 1) < 0;
});
};
or in CoffeeScript:
Array.prototype.unique = ->
this.filter( (value, index, array) ->
array.indexOf(value, index + 1) < 0
)
Finding unique Array values in simple method
function arrUnique(a){
var t = [];
for(var x = 0; x < a.length; x++){
if(t.indexOf(a[x]) == -1)t.push(a[x]);
}
return t;
}
arrUnique([1,4,2,7,1,5,9,2,4,7,2]) // [1, 4, 2, 7, 5, 9]
It appears we have lost Rafael's answer, which stood as the accepted answer for a few years. This was (at least in 2017) the best-performing solution if you don't have a mixed-type array:
Array.prototype.getUnique = function(){
var u = {}, a = [];
for (var i = 0, l = this.length; i < l; ++i) {
if (u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
}
If you do have a mixed-type array, you can serialize the hash key:
Array.prototype.getUnique = function() {
var hash = {}, result = [], key;
for ( var i = 0, l = this.length; i < l; ++i ) {
key = JSON.stringify(this[i]);
if ( !hash.hasOwnProperty(key) ) {
hash[key] = true;
result.push(this[i]);
}
}
return result;
}
strange this hasn't been suggested before.. to remove duplicates by object key (id below) in an array you can do something like this:
const uniqArray = array.filter((obj, idx, arr) => (
arr.findIndex((o) => o.id === obj.id) === idx
))
For an object-based array with some unique id's, I have a simple solution through which you can sort in linear complexity
function getUniqueArr(arr){
const mapObj = {};
arr.forEach(a => {
mapObj[a.id] = a
})
return Object.values(mapObj);
}

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

Adding all matching values of objects in an array (Javascript) (Angular)

What I'm Using
Angular 5
AngularFire5
Firebase & Firestore
What I'm Trying to Achieve
I am trying to cycles through all of the items in an array, which holds objects. If a certain value in the object matches the same value in the other object, then it will add another value together.
Example:
Start With:
mapData = [{"countryCode":"US", "clicks": 5}, {"countryCode":"CAN", "clicks": 9}, {"countryCode":"US", "clicks": 6}]
or
mapData = [["US", 5], ["CAN", 9], ["US", 6]]
End With:
mapDataResults = {
"US": {
"usage": 11,
"fillKey": "tens"
},
"CAN": {
"usage": 9,
"fillKey": "ones"
},
}
Where I'm Stuck
I have no idea on how to search and match through the different object values in the array. Additonally, I would need to figure out how to reorganize how the data is returned, instead of an array it would need to be in a JSON format. Finally, and I think I might be able to figure this out myself, if I can get help with the other parts, but for there to be an additonal value added "fillKey" based on how large the number of clicks (or usage) were.
Assuming your first collection is an array of arrays:
let entries = [["US", 5], ["CAN", 9],["US", 6]];
function getMostSigDigitName(number) {
switch(Math.floor(number).toString().length) {
case 1: return 'ones';
case 2: return 'tens';
}
}
function consolidateAndEmit(a) {
let result = {};
for(let i=0;i<a.length;i++) {
let key = a[i][0];
let val = a[i][1];
if(result[key]) {//exists, so update
result[key].usage += val;
}
else {//does not exist, so add
result[key] = { usage: val};
}
result[key].fillKey = getMostSigDigitName(result[key].usage);
}
return result;
}
consolidateAndEmit(entries);
If you can use lodash, this might be a good one:
mapData = [{"US", 5}, {"CAN", 9},{"US", 6}];
and then _.sumBy(mapData, 'US') or _.sumBy(mapData, "CAN")
All you need to do is map the response to an object. I have given the flow to get the sum and it gets added if mapData array has extra data containing "US" or "CAN".

Maintaining array order in Javascript

I am new to JavaScript and I am having trouble working with my array, I want my array ordered how I explicitly write it and not how JavaScript decides it wants it.
If we have a array
var array = {
0: 'zero',
4: 'four',
2: 'two'
};
When I choose to display this in the console, or iterate over it, Its reordered like this
array = {
0: 'zero',
2: 'two',
4: 'four'
};
I have tried 2 loops so far, The for loop, and also the for loop with the in statement.
Both work according how I assumed they would as they use a key and work there way up/down, making order I specify is absolutely useless.
How can I write/print/work with my array as its ordered, In other languages such as PHP its as simple as
$array = array(
0 => 'zero',
4 => 'four',
2 => 'two'
);
foreach($array as $key => $value)
echo $key ."\n";
This would output
0
4
2
Thanks in advance.
You're using an object {}, not an array []. Objects have no explicit order, where Arrays do. That's why you're having your problem. Change your {} to [] and you'll be fine. You could even use an array of objects.
var array = [
{0: 'zero'},
{4: 'four'},
{2: 'two'}
];
Looping over that like so
for(var i = 0; i < array.length; i++){
console.log(array[i]);
}
Gives us our normal order.
Object {0: "zero"}
Object {4: "four"}
Object {2: "two"}
Another Edit: The problem is you're trying to have an array that has properties and values just like an object, without using an object, {property: value} - that can't really be done with an array. To loop over an array like you want, it's as simple as
var arr = [1,2,3]
and
for(var i = 0; i < arr.length; i++){
console.log(i) //1,2,3
}
but the problem, like mentioned above, is you want more complex arrays which you simply can't do.
You need to understand what an Array and what an Object are, they are fundamentally different things and do not behave the same.
Array
Arrays are list-like objects whose prototype has methods to perform traversal and mutation operations. Neither the length of a JavaScript array nor the types of its elements are fixed. Since an array's size length grow or shrink at any time, JavaScript arrays are not guaranteed to be dense. In general, these are convenient characteristics; but if these features are not desirable for your particular use, you might consider using typed arrays.
Examples of an Array, note the magical length property, the values assigned to an Array are always found at their indexed locations; index is from 0 to 2^32 - 1
// dense arrays
var array1 = [1, 2, 3];
array1.length === 3;
array1[0] === 1;
var array2 = [];
array2[0] = 1;
array2[1] = 2;
array2[2] = 3;
array2.length === 3;
array1[1] === 2;
var array3 = [];
array3.push(1);
array3.push(2);
array3.push(3);
array3.length === 3;
array3[2] === 3;
// and a sparse array
var array4 = [];
array4[0] = 1;
array4[2] = 2;
array4[4] = 3;
array4.length === 5;
array4[1] === undefined;
Iterating an array for
var array = [1, 2, 3, 4, 5];
for (var index = 0; index < array.length; index += 1) { // counts from (index) 0 to 4
console.log(index, array[index]); // outputs 0 1 \n 1 2 \n 2 3 \n 3 4 \n 4 5
}
Object
An object is a collection of properties, and a property is an association between a name and a value. A property's value can be a function, in which case the property is known as a method. In addition to objects that are predefined in the browser, you can define your own objects.
Examples of an Object, there is no magical length property.
var object1 = {
'zero': 1,
'one': 2,
'two': 3
};
object1.zero === 1;
var object2 = {);
object2['zero'] = 1;
object2['one'] = 2;
object2['two'] = 3;
object2.one === 2;
var object3 = {);
object3.zero = 1;
object3.one = 2;
object3.two = 3;
object['two'] === 3;
Iterating (enumerating) an object for..in
var object = {
one: 0,
two: 1,
three: 2
};
for (var property in object) {
if (object.hasOwnProperty(property)) { // make sure the property belongs to object
console.log(property, object[property]); // outputs (not necessarily this order)
// three 2 \n two 1 \n one 0
}
};
If you are trying to maintain an ordered Object, then this is not how Javascript works and iteration (enumeration) of an object is arbitrary. There are techniques that you can use to iterate (enumerate) an Object in a known order. This requires that you keep an ordered list of properties in an array and use the array in the iteration process.
var object = {
'c': 1,
'z': 2,
'b': 3,
'a': 4
}
var propertyOrder = ['c', 'z', 'b', 'a'];
for (var index = 0; index < propertyOrder.length; index += 1) {
console.log(index, propertyOrder[index], object[propertyOrder[index]]); // outputs 0 c 1 \n 1 z 2 \n 2 b 3 \n 3 a 4
}
I don't get it. What makes you think that 0, then 4, then 2, is in any form or shape "in order"?
However, apparently what you want is to keep the number and the string together, in the order that you specify.
Your mistake, if you'll excuse me for perhaps sounding a bit harsh, is that you seem to think that you can use indices or member names to be both a means to access data and part of the data itself.
You can't, and you shouldn't. An index is an index, a name is a name, and data is data [1].
Here are two implementations of keeping your numbers and strings together:
var pairs = [
[0, "zero"],
[4, "four"],
[2, "two"]
];
for (var index in pairs) {
alert(pairs[index][0] + ": " + pairs[index][1]);
};
For this one, I keep the pairs of numbers and strings together in arrays of their own: the numbers at position 0, the strings at position 1. I store these arrays in pairs.
Then I iterate over array with for/in, which, in each iteration, gives me an index of my pairs array.
I then use that index to access the right sub-array in pairs, and get the number from position 0 and the string from position 1.
var pairs = [
{number: 0, string: "zero"},
{number: 4, string: "four"},
{number: 2, string: "two"}
];
for (var index in pairs) {
alert(pairs[index].number + ": " + pairs[index].string);
};
This one works exactly the same, except of storing the pairs in arrays, I store them in objects.
This has the added bonus of better readability inside the for loop: pairs[index][0] and pairs[index][1] do not really convey a clear meaning. It tells us nothing more than, "of the pair with the given index, get items 0 and 1".
However, pairs[index].number and pairs[index].name are much clearer: "of the pair with the given index, give me the number and the name."
_
Footnotes:
[1a] A number is a number: my bank account number is just that: a means to identify my bank account. It doesn't convey any meaning as to my name, my PIN, or the balance on my account -- all attributes that would qualify as data belonging to my bank account.
[1b] A name is a name: my name is just a name. When you're talking about me, you can use my name to refer to me, so that others know whom you are talking about. My name does not convey any information about my hobbies, my SSN, or what brand of car I have -- all attributes that would qualify as data that would describe certain aspects of me. (However, by convention, you can often tell a person's gender by their name)

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