Javascript delete array result is leaving a comma - javascript

Im trying to remove a entery from the array, but after the loop, it leaves an comma seperator where the removed result is.
Q: How can i remove the comma from the array?
wanted output:
after loop
[{ number: 10, count: 1 }, { number: 5, count: 1 } ]
My current code:
console.log("before loop:");
console.log(bNumbersCount);
for(var key in bNumbersCount) {
var card = bNumbersCount[key];
if (card['count'] != x) {
delete bNumbersCount[key];
}
}
console.log("after loop");
console.log(bNumbersCount);
console log result:
before loop:
[ { number: 2, count: 3 },
{ number: 10, count: 1 },
{ number: 5, count: 1 } ]
after loop
[ , { number: 10, count: 1 }, { number: 5, count: 1 } ]

This isn't how you work with arrays in JavaScript.
Don't use for-in on a JavaScript array unless you know what you're doing and have a specific reason; instead, use any of the several other ways outlined in this answer.
Don't use delete on an array entry unless you know what you're doing and want to create a sparse array.
You probably wanted to loop through the array and actually remove entries. Two ways to do that:
Create a new array with only the entries you don't want to remove, via filter:
aNumbersCount = aNumbersCount.filter(function(entry) {
return card.count == x;
});
Use splice to modify your existing array in place, in which case you'll probably want to loop backward so the array indexes don't change on you:
for (var n = aNumbersCount.length - 1; n >= 0; --n) {
if (aNumbersCount[n].count != x) {
aNumbersCount.splice(n, 1); // Removes one entry at index n
}
}
Side note: card['count'] can more simply be written card.count. You only need brackets notation and a string when the name of the property comes from an expression (such as getting a value from a variable) or if the name contains characters that make it an invalid IdentifierName (such as spaces).

Iterate backwards and use splice for deleting.
var array = [ { number: 2, count: 3 }, { number: 10, count: 1 }, { number: 5, count: 1 } ],
i = array.length,
x = 3;
while (i--) {
if (array[i].count === x) {
array.splice(i, 1);
}
}
console.log(array);

You could use filter for that:
bNumbersCount = bNumbersCount.filter(card => card.count === x);
var bNumbersCount = [ { number: 2, count: 3 },
{ number: 10, count: 1 },
{ number: 5, count: 1 } ],
x = 1;
bNumbersCount = bNumbersCount.filter(card => card['count'] === x);
console.log(bNumbersCount);
The delete method does not shift the array elements to fill up the property (index) you deleted. You could use splice for that: that will shift the elements into place. But then you need to take care how you loop, as you can find your self skipping the value that followed just after the deleted/spliced value.
All this becomes more simple with .filter().
NB: Be aware that with .filter you actually create a new array. This means that if you had passed that array as function argument, the caller will not see the change. The function should then return that array to make it available to the caller.

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

What role does the parameter `{count}` play in the following `reduce` call? [duplicate]

This question already has answers here:
What do curly braces inside of function parameter lists do in es6?
(3 answers)
Closed 4 years ago.
This is a snippet of JavaScript. The reduce function is being called to count a number of occurrences, and return the count to the variable total. The reduce function call can be generalized as reduce(array, someFunction, start){function body}.
The specific instance of reduce being used below is of the form reduce(array, (a,b) => a + b, 0). In the snippet below, how is the expression {count} being used, and why is it wrapped in curly {} brackets?. It seems to me it is neither a function body nor an object.
let total = scripts.reduce((n, {count}) => n + count, 0);
if (total == 0) return "No scripts found";
It iterates through an array of objects where these objects have count property. It extracts that property and sums those values.
Here the output is 6 when you sum 1, 2 and 3.
const scripts = [
{ count: 1, something: 'else' },
{ count: 2, foo: 'bar' },
{ count: 3, baz: '23', arr: [1, 2, 3] }
];
let total = scripts.reduce((n, {count}) => n + count, 0);
console.log(total);
It is called object destructuring, more simple example would be.
const obj = { count: 3, foo: 'bar' };
const { count } = obj; // <- extracts value from count property
console.log(count);

Get difference between arrays with same objects

I have two arrays, like this:
var a = [
{id: 1}, {id: 2}, {id: 1}, {id: 3}
];
var b = [
{id: 1}, {id: 3}
];
I want to get the elements that array a has and array b doesn't. The expected outcome is:
[
{id: 1}, {id: 2}
]
I tried this:
a.filter(x => b.indexOf(x) == -1);
And this:
a.filter(x => new Set(b).has(x) == false);
The problem with those two is that it treats {id: 2} from array A and {id: 2} from array B as different objects, so those two lines of code simply return the full array A.
Another difficulty, I need {id: 1} and {id: 1} to be treated as two different objects, even if they have the exact same properties and values inside.
In my actual code, I have objects which are more complex and have more properties, but the situation is the same.
You could take a set and return the filtered array without the values of the set's id.
var a = [{ id: 1 }, { id: 2 }, { id: 1 }, { id: 3 }],
b = [{ id: 2 }, { id: 3 }],
s = new Set(b.map(({ id }) => id)),
result = a.filter(({ id }) => !s.has(id));
console.log(result);
I eventually got this working:
function differenceOf(arr1, arr2) {
var differences = $.extend(true, [], arr1); // creates clone
var arr2Duplicate = $.extend(true, [], arr2);
arr2Loop:
for(var i = 0; i < arr2Duplicate.length; i++) {
var obj2 = arr2Duplicate[i];
if(obj2 == null) continue;
differencesLoop:
for(var j = 0; j < differences.length; j++) {
var obj1 = differences[j];
if(obj1 == null) continue;
if(obj1.id == obj2.id) {
differences.splice(j, 1);
arr2Duplicate.splice(i, 1);
i = -1;
j = -1;
break differencesLoop;
}
}
}
return differences;
}
I cloned the two arrays for future manipulation, so references would be removed and the original arrays wouldn't be affected. I set the first array to be the differences array, so I can delete the elements that appear in the other array.
I iterate through the second array and then inside that loop I iterate through the first array. Then, I check for equal ID's; if so, then I found an element that is in both arrays, so I simply remove it from the first array. I also remove the element from the second array to prevent duplicate comparison, and then I break out of the loop to prevent more deletion of elements with the same ID.
When I remove the elements, the loop is still going, and eventually it'll reach that empty slot where the element used to be, so I check if it's null; if so, skip and keep going.
After both loops finish, I'm left with an array that has the elements that are different, regardless of elements that have the same properties.
EDIT: I changed the jQuery each loops to standard for loops because when I tried to break out of the inner loop, it broke out of the outer loop as well. I fixed this by adding those GOTO labels, which fixed the breaking problem.
When I detected a duplicate, I also reset the indices back to -1, because when the loop continues, the index will increment and skip over objects, leading to incorrect data. I reset it to -1 so that when the code block finishes, it'll increment back to 0 and it'll scan the arrays over again.

Remove elements from array except particular one

I have two arrays. First one is an array of indexes and second one is an array of objects. They look like this:
var nums = [0, 2];
var obj = [Object_1, Object_2, Object_3];
In this particular case I need to remove all "obj" elements except obj[0] and obj[2]. So the result will look like this:
obj = [Object_2]
There are also may be cases when nums = [0, 1, 2] and obj = [Object_1, Object_2, Object_3]; In that case I dont need to remove any elements.
The "obj" length is always greater than "nums" length.
So I started with finding only the elements that I need to save:
nums.forEach(function(key) {
obj.forEach(function(o, o_key) {
if (key === o_key) {
console.log(key, o);
// deleting remaining elements
}
});
});
The question: How can I remove elements that dont meets my condition? I dont need the new array, I want to modify the existing "obj" array. How can I achieve this functionality? Or should I use some another techniques?
You coudld check if the length of the indices is the same length of the object array and return or delete the objects at the given indices.
It needs a sorted array for indices, because Array#splice changes the length of the array. (With an array with descending sorted indices, you could use Array#forEach instead of Array#reduceRight.)
function mutate(objects, indices) {
if (objects.length === indices.length) {
return;
}
indices.reduceRight(function (_, i) {
objects.splice(i, 1);
}, null);
}
var objects = [{ o: 1 }, { o: 2 }, { o: 3 }];
mutate(objects, [0, 1, 2]); // keep all items
console.log(objects);
objects = [{ o: 1 }, { o: 2 }, { o: 3 }]; // delete items at index 0 and 2
mutate(objects, [0, 2]);
console.log(objects);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can do this with a filter, assuming nums is an array on indexes of elements you want to keep.
obj = obj.filter((o, i) => nums.indexOf(i) > -1);
If you want to keep the same array object, you need to use splice e.g. in a simple reverse for in order to not mess the indices:
for (var i=obj.length-1; i>=0; i--) {
if (nums.indexOf(i) < 0) {
obj.splice(i, 1);
}
}
This is assuming the list of indices (nums) is ordered. If not, we first need to sort it:
var sortedNums = nums.sort(function (a, b) { return a - b; });
And then use the sortedNums to check the indexOf

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

Categories