Performance of indexOf() vs. an Associative Array in Javascript? - javascript

I have a series of values which correspond to certain numbers. There are never two values that correspond to the same number. There are no gaps between the numbers.
E.G.
{a: 1, b: 2, c: 3, d: 4}
as opposed to
{a: 1, b: 3, c: 4, d: 7}
Right now, I store the values in an array and find the index of that value. The index in the array is the number that value corresponds with.
Assume the arrays are prepopulated. My questions is which is more efficient to find the corresponding numbers in Javascript:
Store the values in specific positions of an array and find the index with indexOf().
---or---
Store the values and numbers as key value pairs in an associative array.

from what you are saying...
a should be zero as the array starts from index zero and not 1
CASE numeric array:{a: 1, b: 2, c: 3, d: 4}
for loop is suitable
var a = [];
a[5] = 5;
for (var i=0; i<a.length; i++) {
// Iterates over every single numeric indexes from 0 to 5
}
CASE a value is skipped:{a: 1, b: 3, c: 4, d: 7}
for..in is suitable
var a = [];
a[5] = 5;
for (var x in a) {
ignores 0-4,shows only 5
}
CASE Associative array: indexof is suitable
NOTE: It is considered bad practice for iterating through arrays,but not for iterating through members of an object.

Related

How to map two arrays based on comparative value

I have two arrays:
A sequential array of numbers between 1-8, in increments of 1:
a = [1,2,3,4,5,6,7,8]
A sequential array of numbers between 1-8, with random increments:
b = [1,2,5,7]
I want to create a list of {a:val, b:val} dict pairs, where the value of b is only the next in the array if it is equal or greater to the value of a:
c = [
{a:1, b:1},
{a:2, b:2},
{a:3, b:2},
{a:4, b:2},
{a:5, b:5},
{a:6, b:5},
{a:7, b:7},
{a:8, b:7}
]
Is there an easy way to do this? I thought about using compounding $.each loops to build new arrays and increment values, but it seems as though this is overkill?
You can use map and shift
Loop over first array.
If the value of current element is greater then first element on second array remove first element from second array, ( except when the length is less then 2)
return object in desired format
let a = [1, 2, 3, 4, 5, 6, 7, 8]
let b = [1, 2, 5, 7]
let final = a.map(v => {
if (v >= b[1] && b.length > 1) {
b.shift()
}
return {
a: v,
b: b[0]
}
})
console.log(final)
This mutates second array if you don't want to mutate you can use a index variable and increment it based on condition
let a = [1, 2, 3, 4, 5, 6, 7, 8]
let b = [1, 2, 5, 7]
let index = 0
let final = a.map(v => {
if (v >= b[index+1] && b.length - 1 > index ) {
index++
}
return {
a: v,
b: b[index]
}
})
console.log(final)
The first array is actually redundant - the only significant information it carries is the number of elements.
The following code determines the difference between 2 adjacent threshold values from array b. This is 1 less the number of array elements with object property b set to the lower of these threshold values.
The target array is constructed as the array of object properties b in proper order. The resulting value list is mapped to the desired format.
The code may be optimized. It should run fast if the length of array b is much less than the length of array a. This hypothesis is not tested though and given the low complexity of the code/data structures will probably be insignificant.
let a = [1, 2, 3, 4, 5, 6, 7, 8]
, b = [1, 2, 5, 7]
, c = []
, n_last = 1
;
b.forEach ( (pn_current, pn_idx) => {
c.push( ...((new Array(pn_current - n_last)).fill(n_last)) );
n_last = pn_current;
});
c.push( ...((new Array(a.length + 1 - n_last)).fill(n_last)) );
c = c.map ( ( pn_entry, pn_idx ) => { return { a: pn_idx+1, b: pn_entry }; } );
console.log(c);

Array of Objects ordered by similarity to neighbour

I really hope you can help me I have an array of objects and I need an algorithm or a pointer to something to read up on that will sort them by similarity to their neighbours.
For Example
[
{a:12,b: 7,c: 5},
{a: 5,b: 5,c: 5},
{a: 3,b: 3,c: 3},
{a: 5,b: 7,c: 5},
{a:12,b: 7,c: 5}
]
becomes
[
{a: 5,b: 5,c: 5},
{a: 5,b: 7,c: 5},
{a:12,b: 7,c: 5},
{a:12,b: 7,c: 5},
{a: 3,b: 3,c: 3},
]
I have a REPL here...
https://repl.it/#idrise/ThoseWellmadeMonitors
I have brute forced it but it doesn't get the best score and it takes eons on big arrays.
This is how the score is calculated, the higher the score the better !
function scoreArray(array) {
let score = 0;
for (let f = 1; f < array.length; f++) {
score += howSimilarAreObjects(array[f - 1], array[f]);
}
return score;
}
function howSimilarAreObjects(object1, object2) {
let score = 0;
Object.keys(object1).forEach(curValue => {
if (object1[curValue] === object2[curValue]) {
score++;
}
});
return score;
}
Any help greatly appreciated,
Idris
You could run every element against each other and get the similarity between the both objects. Then take the groups and get the objects with the highest similarity first and then with the lower ones. By pushing them to the result set, filter the array by already seen objects.
const similar = (a, b) => Object.keys(a).filter(k => a[k] === b[k]).length;
var array = [{ a: 12, b: 7, c: 5}, { a: 5, b: 5, c: 5}, { a: 3, b: 3, c: 3}, { a: 5, b: 7, c: 5}, { a: 12, b: 7, c: 5}],
groups = {},
used = new Set,
result = [];
array.forEach((a, i) =>
array
.slice(i + 1)
.forEach(b => (s => (groups[s] = groups[s] || []).push(a, b))(similar(a, b))));
Object
.keys(groups)
.reverse()
.forEach(k => result.push(...groups[k].filter(o => !used.has(o) && used.add(o))));
console.log(result);
console.log(groups);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Let us define a function that you wish to minimize:
minimal sum of squared distance between every pair of neighbors
If you were to iterate over all n! permutations, and choose the lowest total, you would have achieved your goal. Of course, n! is way too expensive, so we have to use something simpler.
You can take a greedy approximation, which is simply:
start by any neighbor
continue with the nearest neighbor to the last-added one
repeat 2 until you finish
This will not be optimal, but will not be too far off either. And it is quite cheap to calculate (O(n^2), intead of O(n!)).
Using this function, you are essentially trying to solve the traveling salesman problem (TSP), on which a lot has been written, and for which a lot of approximations exist. The general problem is np-hard, so the normal approach is to choose a not-so-expensive approximation, of which the simplest may be the greedy approach outlined above.

What is the time complexity of JSON.stringify()?

According to this answer, the time complexity of JSON.parse() is O(n).
Does this hold true for JSON.stringify()? There does not appear to be anywhere that documents this.
It should be O(n), but n is the number of nodes in the entire object hierarchy of the value being stringified. So if you have an array of numbers, n is array.length. But if you have an object like:
var obj =
{ a: [1, 2, 3],
b: { x: 1, y: z },
c: { q: [1, 2], r: "abc" }
}
n is 3 (properties of obj) + 3 (elements of obj.a) + 2 (elements of obj.b) + 2 (elements of obj.c) + 2 (elements of obj.c.q) = 12
This also treats stringifying strings as constant, but in actuality they're O(n) where n` is the length of the string. But unless you have lots of long strings in the object, the difference is probably not significant.

Why is the index of an array a string in the below code? [duplicate]

This question already has answers here:
Why does javascript turn array indexes into strings when iterating?
(6 answers)
Is a JavaScript array index a string or an integer?
(5 answers)
Why is key a string in for ... in
(3 answers)
When iterating over values, why does typeof(value) return "string" when value is a number? JavaScript
(1 answer)
Closed 4 years ago.
var arrayOfNumbers = [1, 2, 3, 4, 5, 6, 78];
for(var index in arrayOfNumbers){
console.log(index+1);
}
The output for this sample code is.
01
11
21
31
41
51
61
Why are these indexes of an array treated as a string in JavaScript?
From MDN for...in
Note: for...in should not be used to iterate over an Array where the index order is important.
... The for...in loop statement will return all enumerable properties,
including those with non–integer names and those that are inherited.
When using for...in, the key is always a string and all it does is string concatenation.
You have an array, so better use Array.foreach() like so:
var arrayOfNumbers = [1, 2, 3, 4, 5, 6, 78];
arrayOfNumbers.forEach(function(item, index){
console.log(index + 1); // Here the index is a number!
});
A key is a string, because it is an object. In JavaScript there is Object and that's why its keys are in string.
You can achieve this by converting the string into int or add the prefix +.
var arrayOfNumbers = [1, 2, 3, 4, 5, 6, 78];
for(var index in arrayOfNumbers) {
var v = parseInt(index) + 1;
console.log(v);
}
With a prefix
var arrayOfNumbers = [1, 2, 3, 4, 5, 6, 78];
for(var index in arrayOfNumbers) {
var v = parseInt(index) + 1;
console.log(v);
}
var arrayOfNumbers = [1, 2, 3, 4, 5, 6, 78];
for(var index in arrayOfNumbers){
var v = +index + 1;
console.log(v);
}
Don’t use "for in" for an array. 'for in' is meant for traversing the object. When you try it with an array, it looks like this:
arr = {
"0": 1,
"1": 2,
"2": 3,
"3": 4,
"4": 5,
"5": 6,
"6": 78
}
I hope you are looking for this:
var arrayOfNumbers = [1, 2, 3, 4, 5, 6, 78];
for(var index=0; index<arrayOfNumbers.length; index++) {
console.log(index+1);
}
Reference: MDN FOR..IN
The for...in statement iterates over the enumerable properties of an object. For each distinct property, statements can be executed.
var string1 = "";
var object1 = {a: 1, b: 2, c: 3};
for (var property1 in object1) {
string1 = string1 + object1[property1];
}
console.log(string1);
In your case the indexes are referred to as object keys, which is a t string or a key string : { foo : 'something in universe'}
Have a look here, if you want the key's value:
var arrayOfNumbers = [1, 2, 3, 4, 5, 6, 78];
for(var index in arrayOfNumbers) {
console.log(arrayOfNumbers[index+1]);
}
console.log(arrayOfNumbers)
As stated in the comments and some answers, a for in loop is intended for object iterations, and in JavaScript arrays are objects as well. So the keys will be of type string.
However, for your intended result, you could use something like this:
var arrayOfNumbers = [1, 2, 3, 4, 5, 6, 78];
arrayOfNumbers.forEach(function(num)
{
console.log(num+1);
});
From for...in (MDN):
The for...in statement iterates over the enumerable properties of an object.
So the value of index in your code will always return the names of those properties. In an array, those are the names of the indexes.
Also, a String plus a Number equals a String which is what is printed in the console.

How to remove duplicates from a typescript array? [duplicate]

This question already has answers here:
How to remove all duplicates from an array of objects?
(77 answers)
Closed 5 years ago.
Could you let me know how do I remove duplicates from an Array in type script.
My array will look something like
a = [{a: 1, b: 2}, {a: 1, b: 2}, {c: 3, d: 4}]
I am looking to get
a = [{a: 1, b: 2}, {c: 3, d: 4}]
I used Set data strucure like below
a = Array.from(new Set(a))
but still no use. Please let me know how to remove duplicates from an array using single statement?
Is not in a single statement but is short.
var a = [{a: 1, b: 2}, {a: 1, b: 2}, {c: 3, d: 4}];
a = a.filter((value, index, array) =>
!array.filter((v, i) => JSON.stringify(value) == JSON.stringify(v) && i < index).length);
console.log(a);
Your question sees like this:
Delete duplicated elements in array of objects Javascript
But like in the comment will fails for:
var a = [{a: 1, b: 2}, {b: 2, a: 1}];
You need a custom compare for your case:
function isEqual(a, b){
for(var i in a)
if(a[i] != b[i])
return false;
for(var i in b)
if(b[i] != a[i])
return false;
return true;
}
var a = [{a: 1, b: 2}, {b: 2, a: 1}, {c: 3, d: 4}];
a = a.filter((value, index, array) =>
!array.filter((v, i) => isEqual(value, v) && i < index).length);
console.log(a);
You can compare ids or somenthing like this to identify equal object in this sample i just compare the properties.
Like #Juan Mendes said in comment:
The reason your code doesn't filter elements is because two similar objects are still considered different objects because they point to different objects. You need to write your own code that uses a custom comparator.

Categories