Given this input [3,1,2] I want to have this output [ [ 1, 1 ], [ 1, 2 ], [ 1, 3 ], [ 2, 2 ], [ 2, 3 ], [ 3, 3 ] ]
Its the unique pairs ([1,2] == [2,1])
Currently I've made that
const arr = [3,1,2];
const pairBuilder = (left, index, collection) =>
collection.slice(index).map(right => [left, right]);
const pairs = arr.sort().flatMap(pairBuilder);
console.log(pairs)
This code is functional, but I wonder if there is not a better way (in terms of performances) to achieve this ? I've though of using lodash to improve sorting / mapping (with chain), but my question is more about algorithm improvement.
You could use a Generator with a function* and slice the array for getting only unique pairs.
function* getPairs(array, left) {
var i = 0;
while (i < array.length) {
if (left) yield [left, array[i]];
else yield* getPairs(array.slice(i), array[i]);
i++;
}
}
var array = [1, 2, 3];
console.log([...getPairs(array)]);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A classic approach.
function getPairs(array) {
var i, j, result = [];
for (i = 0; i < array.length; i++) {
for (j = i; j < array.length; j++) {
result.push([array[i], array[j]]);
}
}
return result;
}
var array = [1, 2, 3];
console.log(getPairs(array));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is a naive and slow approach.
But i beleive it is faster than accepted answer and answer in the question.
It generates less new objects overhead and requires less memory.
Naive algorithm doesn't use recursion. so does not face recursion limit (50 by default)
Also i beleive it's still readable and easy to understand
const inp = [3, 1,2];
function genPair(inp) {
const length = inp.length;
const sorted = inp.sort();
const result = [];
for (let i = 0; i < length; i++) {
for (let j = i; j < length; j++) {
result.push([sorted[i], sorted[j]]);
}
}
return result;
}
const r = genPair(inp);
console.log(r);
link to js perf
https://jsperf.com/find-dups/1
Accepted answer in IE11 60% slower and in Chrome 10% slower
Related
Please help me to solve this leetcode problem using javascript as I am a beginner and dont know why this code is not working
Ques: Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.
Find all the elements of [1, n] inclusive that do not appear in this array.
var findDisappearedNumbers = function (nums) {
var numLength = nums.length;
nums.sort(function (a, b) { return a - b });
for (var i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] === nums[i]) {
nums.splice(i, 1);
}
}
for (var k = 0; k < nums.length; k++) {
for (var j = 1; j <= numLength; j++) {
if (nums[k] !== j) {
return j;
}
}
}
};
if there is any error in my code please let me know;
i have done the following thing
first i have sorted the array in ascending order
then i have cut all the duplicate elements
then i have created loop that will check if nums[k] !== j ;
and it will return j which is the missing number;
for example this is the testcase [4,3,2,7,8,2,3,1]
first my code will sort this in ascending order [1,2,2,3,3,4,7,8]
then it will remove all duplicate elements and it will return [1,2,3,4,,7,8]
and then it will check nums[k] is not equal to j and it will print j
I think it'd be easier to create a Set of numbers from 1 to n, then just iterate through the array and delete every found item from the set:
var findDisappearedNumbers = function(nums) {
const set = new Set();
for (let i = 0; i < nums.length; i++) {
set.add(i + 1);
}
for (const num of nums) {
set.delete(num);
}
return [...set];
};
console.log(findDisappearedNumbers([4,3,2,7,8,2,3,1]));
To fix your existing code, I'm not sure what the logic you're trying to implement in the lower section, but you can iterate from 1 to numLength (in the outer loop, not the inner loop) and check to see if the given number is anywhere in the array. Also, since you're mutating the array with splice while iterating over it in the upper loop, make sure to subtract one from i at the same time so you don't skip an element.
var findDisappearedNumbers = function(nums) {
var numLength = nums.length;
nums.sort(function(a, b) {
return a - b
});
for (var i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] === nums[i]) {
nums.splice(i, 1);
i--;
}
}
const notFound = [];
outer:
for (var j = 1; j < numLength; j++) {
for (var k = 0; k < nums.length; k++) {
if (nums[k] === j) {
continue outer;
}
}
notFound.push(j);
}
return notFound;
};
console.log(findDisappearedNumbers([4, 3, 2, 7, 8, 2, 3, 1]));
#CertainPerformance certainly cracked it again using the modern Set class. Here is a slighly more conservative approach using an old fashioned object:
console.log(missingIn([4,3,2,7,8,2,3,1]));
function missingIn(arr){
const o={};
arr.forEach((n,i)=>o[i+1]=1 );
arr.forEach((n) =>delete o[n] );
return Object.keys(o).map(v=>+v);
}
My solution for the problem to find the missing element
var findDisappearedNumbers = function(nums) {
const map={};
const result=[];
for(let a=0;a<nums.length;a++){
map[nums[a]]=a;
}
for(let b=0;b<nums.length;b++){
if(map[b+1]===undefined){
result.push(b+1)
}
}
return result;
};
Example 1:
Input: nums = [4,3,2,7,8,2,3,1]
Output: [5,6]
Example 2:
Input: nums = [1,1]
Output: [2]
This question already has answers here:
Javascript ES6 computational/time complexity of collections
(3 answers)
Closed 3 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Duplicate This question has been answered, is not unique, and doesn’t differentiate itself from another question.
I have seen in an answer that the Set.has() method is O(1) and Array.indexOf() is O(n).
var a = [1, 2, 3, 4, 5];
a.indexOf(5);
s = new Set(a);
s.has(5); //Is this O(1)?
Is Set.has() really O(1) ?
I don't think the array that has 5 elements is good case to check time complexity.
So based on #Shidersz's snippet, I made a new one that has many elements and invoked once.
Is Set.has() really O(1) ?
Yes. Time complexity of Set.has() is O(1) according to result of the test below.
const MAX = 10000000
let a = []
a.length = MAX
for (let i = 0; i < MAX; i++) {
a[i] = i
}
let s = new Set(a)
let o = a.reduce((acc, e) => {
acc[e] = e
return acc
}, {})
console.time("Test_Array.IndexOf(0)\t")
a.indexOf(0);
console.timeEnd("Test_Array.IndexOf(0)\t")
console.time("Test_Array.IndexOf(n/2)\t")
a.indexOf(MAX / 2);
console.timeEnd("Test_Array.IndexOf(n/2)\t")
console.time("Test_Array.IndexOf(n)\t")
a.indexOf(MAX);
console.timeEnd("Test_Array.IndexOf(n)\t")
console.time("Test_Set.Has(0)\t\t")
s.has(0)
console.timeEnd("Test_Set.Has(0)\t\t")
console.time("Test_Set.Has(n/2)\t")
s.has(MAX / 2)
console.timeEnd("Test_Set.Has(n/2)\t")
console.time("Test_Set.Has(n)\t\t")
s.has(MAX)
console.timeEnd("Test_Set.Has(n)\t\t")
console.time("Test_Object[0]\t\t")
o[0]
console.timeEnd("Test_Object[0]\t\t")
console.time("Test_Object[n/2]\t")
o[MAX / 2]
console.timeEnd("Test_Object[n/2]\t")
console.time("Test_Object[n]\t\t")
o[MAX]
console.timeEnd("Test_Object[n]\t\t")
.as-console {
background-color: black !important;
color: lime;
}
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
If one read the specification of has(), there is an algorithm describing it:
Algorithm for Set.prototype.has(value):
The following steps are taken:
Let S be the this value.
If Type(S) is not Object, throw a TypeError exception.
If S does not have a [[SetData]] internal slot, throw a TypeError exception.
Let entries be the List that is the value of S’s [[SetData]] internal slot.
Repeat for each e that is an element of entries,
If e is not empty and SameValueZero(e, value) is true, return true.
Return false.
And apparently, based on that algorithm and the presence of the word REPEAT one can have some confusion about it to be O(1) (we could think it could be O(n)). However, on the specification we can read that:
Set objects must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements in the collection.
Thanks to #CertainPerformance for pointing this.
So, we can create a test to compare Array.indexOf() and Set.has() in the worst case, i.e. look for an item that isn't in the array at all (thanks to #aquinas for pointing this test):
// Initialize array.
let a = [];
for (let i = 1; i < 500; i++)
{
a.push(i);
}
// Initialize set.
let s = new Set(a);
// Initialize object.
let o = {};
a.forEach(x => o[x] = true);
// Test Array.indexOf().
console.time("Test_Array.indexOf()");
for (let i = 0; i <= 10000000; i++)
{
a.indexOf(1000);
}
console.timeEnd("Test_Array.indexOf()");
// Test Set.has().
console.time("Test_Set.has()");
for (let i = 0; i <= 10000000; i++)
{
s.has(1000);
}
console.timeEnd("Test_Set.has()");
// Test Object.hasOwnProperty().
console.time("Test_Object.hasOwnProperty()");
for (let i = 0; i <= 10000000; i++)
{
o.hasOwnProperty(1000);
}
console.timeEnd("Test_Object.hasOwnProperty()");
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
And now we can see that Set.has() performs better than Array.indexOf(). There is also an extra comparison to Object.hasOwnProperty() to take as reference.
Conclusion:
While O(1) complexity isn't guaranteed, the specification requires the method to run in sublinear time. And Set.has(), generally, will perform better than Array.indexOf().
Another Test:
On next example, we going to generate a random set of sample data and use it later to compare the differents methods.
// Generate a sample array of random items.
const getRandom = (min, max) =>
{
return Math.floor(Math.random() * (max - min) + min);
}
let sample = Array.from({length: 10000000}, () => getRandom(0, 1000));
// Initialize array, set and object.
let a = [];
for (let i = 1; i <= 500; i++)
{
a.push(i);
}
let s = new Set(a);
let o = {};
a.forEach(x => o[x] = true);
// Test Array.indexOf().
console.time("Test_Array.indexOf()");
for (let i = 0; i < sample.length; i++)
{
a.indexOf(sample[i]);
}
console.timeEnd("Test_Array.indexOf()");
// Test Set.has().
console.time("Test_Set.has()");
for (let i = 0; i < sample.length; i++)
{
s.has(sample[i]);
}
console.timeEnd("Test_Set.has()");
// Test Object.hasOwnProperty().
console.time("Test_Object.hasOwnProperty()");
for (let i = 0; i < sample.length; i++)
{
o.hasOwnProperty(sample[i]);
}
console.timeEnd("Test_Object.hasOwnProperty()");
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Finally I want to apologize for the confusion the first version of my answer could cause. Thanks to all for giving me a better understanding of my mistakes.
I have this array [1,2,3]
I would like to be able to set its length to 7
and have this [1,2,3,1,2,3,1] as a result.
Anyone?
const arr = [1,2,3];
// Something like
arr.resize(7);
console.log(arr); // [1,2,3,1,2,3,1]
EDIT:
Based on chevybow answer below i wrote this functions to serve my needs.
// Immutable
Array.prototype.resize = function(size) {
const array = Array(size);
for(let i = 0; i < size; i++) {
array[i] = this[i%this.length];
}
return array;
}
// Mutable
Array.prototype.resize = function(size) {
const array = this.slice(0);
this.length = size;
for(let i = 0; i < size; i++) {
this[i] = array[i%array.length];
}
}
Are those ok? or you think that putting it on the chain is not a good idea, if so why?
You can use modular arithmetic to loop through up to the length of your final array and then use the index to basically loop through and push that onto a new array
Using the current array value % array.length will get you the current position of the array by progressing it in a circular motion
let num = 7;
let array = [1,2,3];
let result = [];
for(let i = 0; i < num; i++){
result.push(array[i%array.length]);
}
console.log(result)
A simple while loop would suffice:
function repeat(arr, toLength) {
let output = [...arr];
while (output.length < toLength) output = [...output, ...arr];
return output.slice(0, toLength);
}
console.log(repeat([1, 2, 3], 7));
console.log(repeat([1, 2, 3], 2));
How about this version:
const nums = [1, 2, 3];
function resize(arr, length) {
let position = 0;
return Array.from(Array(length)).reduce((acc, _, i) => {
return acc.concat(arr[i % arr.length]);
}, []);
}
console.log(resize(nums, 7));
I have 2 arrays in the below:
sonuc_X = [ 41.01766, 41.01746, 41.05877, 41.05974, 41.04383, 41.03693 ];
var labels = ["lat"];
I also have merge processing below:
var obj_X = {};
for (var j = 0; j < labels.length; j++) {
obj_X[labels[j]] = sonuc_X[j];
}
var asJSON = JSON.stringify(obj_X);
console.log(asJSON);
when I combine two sequences at the json, the following result comes out:
{"lat":41.01766}
I expect:
[ "lat":41.01766, "lat":41.01746, "lat":41.05877, "lat":41.05974, "lat":41.04383, "lat":41.03693 ]
?
You could iterate the data and build new objects with the wanted keys.
var data = [41.01766, 41.01746, 41.05877, 41.05974, 41.04383, 41.03693],
keys = ["lat", "lng"],
result = data.reduce(function (r, v, i) {
if (i % keys.length === 0) {
r.push({});
}
r[r.length - 1][keys[i % keys.length]] = v;
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I need to do a simple diagonal matrix in JS, which should look like this one:
[
[4, 7, 9],
[2, 5, 8],
[1, 3, 6]
]
My idea is to use a 2-d array and two loops, but the result I get is an empty array.You'll see below what my code looks like, but obviously I have a problem with the values.
function fillMatrix(n) {
var matrix = [];
var rows = 0;
var cols = 0;
var startCount = 1;
for (var i = (n - 1); i >= 0; i--) {
rows = i;
cols = 0;
matrix[rows] = [];
while (rows < n && cols < n) {
matrix[rows++][cols++] = startCount++;
}
for (var j = 0; j < n; j++) {
rows = j;
cols = 0;
matrix[rows] = [];
while (rows < n && cols < n) {
matrix[cols++][cols++] = startCount++;
}
}
}
return matrix;
}
n = +prompt();
console.log(fillMatrix(n));
The logic for creating a diagonal matrix can be greatly simplified if one looks at the patterns between rows. (I won't go through all of the math here, but feel free to ask me questions in the comments about any specific sections you find confusing.)
Take, for example, the 4x4 diagonal matrix:
Successive differences between elements in a row form the pattern below:
I might still work on shortening the method below, but right now it works and is fairly concise.
Demo:
function diagonalMatrix (n) {
var matrix = [], row
for (var i = n; i > 0; i--) {
var x = i*(i-1)/2 + 1, dx = i
matrix.push(row = [])
for (var j = n; j > 0; j--) {
row.push(x)
x += (i < j ? ++dx : dx--)
}
}
return matrix
}
var matrix = diagonalMatrix(+prompt('Diagonal Matrix Order:'))
console.log(beautify(matrix))
console.log(matrix)
// For visualization purposes
function beautify (matrix) {
return matrix.map(function (e) {
return e.join('\t')
}).join('\n\n\n\n')
}
.as-console-wrapper { min-height: 100vh; }