Populate array with non repeating random numbers - javascript

So I have an array called arr.
I want to populate it with four random numbers:
for (var i = 0; i < 4; i++) {
arr[i] = Math.floor(Math.random() * 10);
}
If that returns an array with values [4, 2, 3, 4]. How do I check for duplicates, and recalculate a random number that doesn't equal any other values that already exist in the array?
Also if there is a better way of accomplishing this, I would love to learn/know that way as well.

Also if there is a better way of accomplishing this, I would love to learn/know that way as well.
There is.
If you need unique values, generate a regular sequential array [1,2,3,4] (or however long you need), and then use that to fill a second array, by successively extracting random elements from the first array (thus growing array 2, and shrinking array 1):
var a1 = [];
for (var i=0; i<4; i++) { a1.push(i); }
var a2 = [];
while (a1.length) {
var pos = Math.random()*a1.length;
var element = a1.splice(pos, 1)[0];
a2.push(element);
}
// a2 is now an array with a random permutation of the elements of a1
The splice call removes an subarray starting at position pos with (in this case) 1 element, so a1 gets shorter and shorter, until it's empty, at which point a2 will be a permuted array of unique values.
If we start with a1 = [0,1,2,3] then after this runs a2 can be any of 24 possible sequences, with guaranteed unique values because that's what we started with, just in a randomised order.

What you are looking for is a way to take a random sample from an array of the integers [0..9]. You can do this with several algorithms, for example a simple reservoir sampling algorithm.

If you want to have an array that contains any amount of numbers from 1 to n in random order, I think the more viable approach is to generate an array with all numbers from 1 to n and then shuffle it as described here.
You can then proceed to splice the array after shuffling to shorten it to the desired length.
Both steps have the complexity of O(1) or O(n), which is far better than testing for every insert or modifying a value pool from which you draw the numbers.

I'd probably make a function for the loop.
function getNumber(arr){
var num = Math.floor(Math.random() * 10);
if(arr.indexOf(num) < 0){
return num;
} else {
getNumber(arr);
};
};
Then you would do:
var arr = [];
for (var i = 0; i < 4; i++) {
arr[i] = getNumber(arr);
}

Related

Why does an object exist in two sum solution? [duplicate]

Im just wondering who can explain the algorithm of this solution step by step. I dont know how hashmap works. Can you also give a basic examples using a hashmap for me to understand this algorithm. Thank you!
var twoSum = function(nums, target) {
let hash = {};
for(let i = 0; i < nums.length; i++) {
const n = nums[i];
if(hash[target - n] !== undefined) {
return [hash[target - n], i];
}
hash[n] = i;
}
return [];
}
Your code takes an array of numbers and a target number/sum. It then returns the indexes in the array for two numbers which add up to the target number/sum.
Consider an array of numbers such as [1, 2, 3] and a target of 5. Your task is to find the two numbers in this array which add to 5. One way you can approach this problem is by looping over each number in your array and asking yourself "Is there a number (which I have already seen in my array) which I can add to the current number to get my target sum?".
Well, if we loop over the example array of [1, 2, 3] we first start at index 0 with the number 1. Currently, there are no numbers which we have already seen that we can add with 1 to get our target of 5 as we haven't looped over any numbers yet.
So, so far, we have met the number 1, which was at index 0. This is stored in the hashmap (ie object) as {'1': 0}. Where the key is the number and the value (0) is the index it was seen at. The purpose of the object is to store the numbers we have seen and the indexes they appear at.
Next, the loop continues to index 1, with the current number being 2. We can now ask ourselves the question: Is there a number which I have already seen in my array that I can add to my current number of 2 to get the target sum of 5. The amount needed to add to the current number to get to the target can be obtained by doing target-currentNumber. In this case, we are currently on 2, so we need to add 3 to get to our target sum of 5. Using the hashmap/object, we can check if we have already seen the number 3. To do this, we can try and access the object 3 key by doing obj[target-currentNumber]. Currently, our object only has the key of '1', so when we try and access the 3 key you'll get undefined. This means we haven't seen the number 3 yet, so, as of now, there isn't anything we can add to 2 to get our target sum.
So now our object/hashmap looks like {'1': 0, '2': 1}, as we have seen the number 1 which was at index 0, and we have seen the number 2 which was at index 1.
Finally, we reach the last number in your array which is at index 2. Index 2 of the array holds the number 3. Now again, we ask ourselves the question: Is there a number we have already seen which we can add to 3 (our current number) to get the target sum?. The number we need to add to 3 to get our target number of 5 is 2 (obtained by doing target-currentNumber). We can now check our object to see if we have already seen a number 2 in the array. To do so we can use obj[target-currentNumber] to get the value stored at the key 2, which stores the index of 1. This means that the number 2 does exist in the array, and so we can add it to 3 to reach our target. Since the value was in the object, we can now return our findings. That being the index of where the seen number occurred, and the index of the current number.
In general, the object is used to keep track of all the previously seen numbers in your array and keep a value of the index at which the number was seen at.
Here is an example of running your code. It returns [1, 2], as the numbers at indexes 1 and 2 can be added together to give the target sum of 5:
const twoSum = function(nums, target) {
const hash = {}; // Stores seen numbers: {seenNumber: indexItOccurred}
for (let i = 0; i < nums.length; i++) { // loop through all numbers
const n = nums[i]; // grab the current number `n`.
if (hash[target - n] !== undefined) { // check if the number we need to add to `n` to reach our target has been seen:
return [hash[target - n], i]; // grab the index of the seen number, and the index of the current number
}
hash[n] = i; // update our hash to include the. number we just saw along with its index.
}
return []; // If no numbers add up to equal the `target`, we can return an empty array
}
console.log(twoSum([1, 2, 3], 5)); // [1, 2]
A solution like this might seem over-engineered. You might be wondering why you can't just look at one number in the array, and then look at all the other numbers and see if you come across a number that adds up to equal the target. A solution like that would work perfectly fine, however, it's not very efficient. If you had N numbers in your array, in the worst case (where no two numbers add up to equal your target) you would need to loop through all of these N numbers - that means you would do N iterations. However, for each iteration where you look at a singular number, you would then need to look at each other number using a inner loop. This would mean that for each iteration of your outer loop you would do N iterations of your inner loop. This would result in you doing N*N or N2 work (O(N2) work). Unlike this approach, the solution described in the first half of this answer only needs to do N iterations over the entire array. Using the object, we can find whether or not a number is in the object in constant (O(1)) time, which means that the total work for the above algorithm is only O(N).
For further information about how objects work, you can read about bracket notation and other property accessor methods here.
You may want to check out this method, it worked so well for me and I have written a lot of comments on it to help even a beginner understand better.
let nums = [2, 7, 11, 15];
let target = 9;
function twoSums(arr, t){
let num1;
//create the variable for the first number
let num2;
//create the variable for the second number
let index1;
//create the variable for the index of the first number
let index2;
//create the variable for the index of the second number
for(let i = 0; i < arr.length; i++){
//make a for loop to loop through the array elements
num1 = arr[i];
//assign the array iteration, i, value to the num1 variable
//eg: num1 = arr[0] which is 2
num2 = t - num1;
//get the difference between the target and the number in num1.
//eg: t(9) - num1(2) = 7;
if(arr.includes(num2)){
//check to see if the num2 number, 7, is contained in the array;
index1 = arr.indexOf(num2);
//if yes get the index of the num2 value, 7, from the array,
// eg: the index of 7 in the array is 1;
index2 = arr.indexOf(num1)
//get the index of the num1 value, which is 2, theindex of 2 in the array is 0;
}
}
return(`[${index1}, ${index2}]`);
//return the indexes in block parenthesis. You may choose to create an array and push the values into it, but consider space complexities.
}
console.log(twoSums(nums, target));
//call the function. Remeber we already declared the values at the top already.
//In my opinion, this method is best, it considers both time complexity and space complexityat its lowest value.
//Time complexity: 0(n)
function twoSum(numbers, target) {
for (let i = 0; i < numbers.length; i++) {
for (let j = i + 1; j < numbers.length; j++) {
if (numbers[i] + numbers[j] === target) {
return [numbers.indexOf(numbers[i]), numbers.lastIndexOf(numbers[j])];
}
}
}
}

Understanding Hashmaps with Javascript

I need help understanding what and how to use hash maps in javascript. I have an example where
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Can someone breakdown what this hashmap solution is doing and why it's better? Also if someone would be kind of enough to give me a similar problem to practice with that would extremely helpful.
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
My BruteForce Solution
for (var i = 0; i < nums.length; i++) {
for (var j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] === target) {
result.push(i);
result.push(j);
}
}
}
return result;
}
console.log(twoSum([2, 7, 11, 15], 9));
HashMapSolution
function twoSumBest(array, target) {
const numsMap = new Map();
for (let i = 0; i < array.length; i++) {
if(numsMap.has(target - array[i])) {
return [numsMap.get(target - array[i], i)];
// get() returns a specified element associated with the specified key from the Map object.
} else {
numsMap.set(array[i], i);
// set() adds or updates an element with a specified key and value to a Map object.
}
}
}
If you want to reach 10 and you have 7, you already know that the other number that is needed is 3. So for every number in the array, you only have to check wether the complementary number is in the array, you don't necessarily have to search for it.
If we go over all array entries once (let's call them a) and add them to a hashmap with their index, we can go over the array again and for each entry (b), we can check if the hashmap contains an a (where a + b = target). If that entry is found, the index of b is known, and the index of a can be retrieved from the hashmap¹. Now using that method we only iterate the array twice (or just once, doesn't matter that much), so if you have 1000 numbers, it'll iterate 1000 times. Your solution will iterate 1000 * 1000 times (worst case). So the hashtable approach is way faster (for larger arrays).
¹ Hashmaps are very special, as the time it takes to look up a key takes a constant amount of time, so it does not matter wether the array has 10 or 10 million entries (the time complexity is constant = O(1)). Thus, looking up in an hashtable is way better than searching inside of an array (which takes more time with more entries = O(n)).

Duplicate an array an arbitrary number of times (javascript)

Let's say I'm given an array. The length of this array is 3, and has 3 elements:
var array = ['1','2','3'];
Eventually I will need to check if this array is equal to an array with the same elements, but just twice now. My new array is:
var newArray = ['1','2','3','1','2','3'];
I know I can use array.splice() to duplicate an array, but how can I duplicate it an unknown amount of times? Basically what I want is something that would have the effect of
var dupeArray = array*2;
const duplicateArr = (arr, times) =>
Array(times)
.fill([...arr])
.reduce((a, b) => a.concat(b));
This should work. It creates a new array with a size of how many times you want to duplicate it. It fills it with copies of the array. Then it uses reduce to join all the arrays into a single array.
The simplest solution is often the best one:
function replicate(arr, times) {
var al = arr.length,
rl = al*times,
res = new Array(rl);
for (var i=0; i<rl; i++)
res[i] = arr[i % al];
return res;
}
(or use nested loops such as #UsamaNorman).
However, if you want to be clever, you also can repeatedly concat the array to itself:
function replicate(arr, times) {
for (var parts = []; times > 0; times >>= 1) {
if (times & 1)
parts.push(arr);
arr = arr.concat(arr);
}
return Array.prototype.concat.apply([], parts);
}
Basic but worked for me.
var num = 2;
while(num>0){
array = array.concat(array);
num--}
Here's a fairly concise, non-recursive way of replicating an array an arbitrary number of times:
function replicateArray(array, n) {
// Create an array of size "n" with undefined values
var arrays = Array.apply(null, new Array(n));
// Replace each "undefined" with our array, resulting in an array of n copies of our array
arrays = arrays.map(function() { return array });
// Flatten our array of arrays
return [].concat.apply([], arrays);
}
console.log(replicateArray([1,2,3],4)); // output: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
What's going on?
The first two lines use apply and map to create an array of "n" copies of your array.
The last line uses apply to flatten our recently generated array of arrays.
Seriously though, what's going on?
If you haven't used apply or map, the code might be confusing.
The first piece of magic sauce here is the use of apply() which makes it possible to either pass an array to a function as though it were a parameter list.
Apply uses three pieces of information: x.apply(y,z)
x is the function being called
y is the object that the function is being called on (if null, it uses global)
z is the parameter list
Put in terms of code, it translates to: y.x(z[0], z[1], z[2],...)
For example
var arrays = Array.apply(null, new Array(n));
is the same as writing
var arrays = Array(undefined,undefined,undefined,... /*Repeat N Times*/);
The second piece of magic is the use of map() which calls a function for each element of an array and creates a list of return values.
This uses two pieces of information: x.map(y)
x is an array
y is a function to be invoked on each element of the array
For example
var returnArray = [1,2,3].map(function(x) {return x + 1;});
would create the array [2,3,4]
In our case we passed in a function which always returns a static value (the array we want to duplicate) which means the result of this map is a list of n copies of our array.
You can do:
var array = ['1','2','3'];
function nplicate(times, array){
//Times = 2, then concat 1 time to duplicate. Times = 3, then concat 2 times for duplicate. Etc.
times = times -1;
var result = array;
while(times > 0){
result = result.concat(array);
times--;
}
return result;
}
console.log(nplicate(2,array));
You concat the same array n times.
Use concat function and some logic: http://www.w3schools.com/jsref/jsref_concat_array.asp
Keep it short and sweet
function repeat(a, n, r) {
return !n ? r : repeat(a, --n, (r||[]).concat(a));
}
console.log(repeat([1,2,3], 4)); // [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
http://jsfiddle.net/fLo3uubk/
if you are inside a loop you can verify the current loop index with the array length and then multiply it's content.
let arr = [1, 2, 3];
if(currentIndex > arr.length){
//if your using a loop, make sure to keep arr at a level that it won't reset each loop
arr.push(...arr);
}
Full Example:
https://jsfiddle.net/5k28yq0L/
I think you will have to write your own function, try this:
function dupArray(var n,var arr){
var newArr=[];
for(var j=0;j<n;j++)
for(var i=0;i<arr.length;i++){
newArr.push(arr[i]);
}
return newArr;
}
A rather crude solution for checking that it duplicates...
You could check for a variation of the length using modulus:
Then if it might be, loop over the contents and compare each value until done. If at any point it doesn't match before ending, then it either didn't repeat or stopped repeating before the end.
if (array2.length % array1.length == 0){
// It might be a dupe
for (var i in array2){
if (i != array1[array2.length % indexOf(i)]) { // Not Repeating }
}
}

Undo sort on sorted array in javascript

I have an array. I sort it.
I get a second array which is already sorted based on the first one.
I need to reverse the sorting on the second array.
For example, if the first array (unsorted) is: [9, 5, 3, 0, 2] then I want to to sort it, so that it becomes [0, 2, 3, 5, 9].
Then I receive the second array sorted based on the first one, for example ["home", "car", "train", "pc", "mouse"]. I need it to become ["mouse, "pc", "train", "home", "car"].
I can't make a copy of the array.
I have the following code:
//data_r is an array with values
var i = 0;
var sort_order = new Array();
data_r.sort(function (a,b) {
var res = a[0] - b[0];
sort_order[i] = res;
i++;
return res;
});
In the end, the the sort_order array will contain the actions performed when we sorted items. If I want to sort a second array exactly the same way as the first then I can do the following:
//data_x is an array with values
var i = 0;
data_x.sort(function (a,b) {
i++;
return sort_order[i-1];
});
Now the data_x array is sorted exactly the same way as the data_r array.
How can I undo sort on the data_r array?
The following code is incorrect:
var unsort = new Array();
for(var i = 0; i < data_r.length; i++)
unsort[i] = sort_order[i]*(-1);//-1 so we perfom the oposite action
Your premise here is flawed.
In the end, the sort_order array contains the actions performed when we sorted items.
No, it doesn't; it contains a log of the comparisons performed by the Javascript Array.sort function. The actions it took in response to those comparison results are private to it.
If I want to sort a second array exactly the same way as the first then I can do the following:
This is not guaranteed to work. Even if the two arrays are the same size, Array.sort may not always compare the same elements in the same order each time it's called - it's possible that it's using a randomized algorithm, that it performs comparisons based on other data that are internal to the interpreter, or that it switches between multiple entirely different sort algorithms under some circumstances.
While this code may work for you, right now, in your current web browser, it is likely to fail in surprising ways in other circumstances (possibly in future browsers). Do not use this technique in production code.
The question is, how can i unsort the data_r array?
Make a copy of the array before you sort it.
Storing res[i] = a - b is like journaling the sort() algorithm - but what if it used a random pivot?
This code is inherently unreliable unless you write sort() yourself. It's also inefficient.
A better approach, one that will solve both your needs, is to create an array of indices and sort that. This is trivial to invert. Then you can implement a permute function that takes an array of indices, and it achieves a sort or unsort, depending on the input.
If x is from 0:n-1, create an array sort_i of same size, then initialize each sort_i[i] = i.
for(var i = 0; i < n; i++)
sort_i[i] = i;
Then
sort_i.sort(function (a,b) { return x[a] - x[b]; });
Now you have the indices. To apply to x:
for(var i = 0; i < n; i++)
sort_x[i] = x[sort_i[i]];
To unsort it, first invert the indices
for(var i = 0; i < n; i++)
unsort_i[sort_i[i]] = i;
Then apply the indices. Exercise left to question asker.
This approach of sorting an array of integer indices is needed when you don't want to move the original elements around in memory (maybe they are big objects), and many other circumstances. Basically you are sorting pointers. The result is an index to the data, and a reverse index.
See #duskwuff's answer on why your approach doesn't work.
Instead, just introduce a mapping between the original data and the sorted data.
{0:2, 1:3, 2:1, 3:0}
Which means the first element became the third, the second became the last and so on. Below we'll use an array instead of an object.
Why does this map help? You can sort it like another dataset by just using the indizes in it as pointers to the data you're going to compare. And you can apply the mapping easily on other datasets. And you can even reverse that mapping very easily. See it in the code:
// data_r, data_x are arrays with values
var l = data_r.length;
var sort_order = new Array(l);
for (var i=0; i<l; i++) sort_order[i] = i; // initialised as 1-1 mapping
// change the sort_order first:
sort_order.sort(function (a,b) {
// a and b being indices
return data_r[a] - data_r[b];
});
// Making a new, sorted array
var data_x_sorted = new Array(l);
for (var i=0; i<l; i++)
data_x_sorted[ sort_order[i] ] = data_x[i]; // put it to sorted position
If you want to sort the data_x array itself, just use the "apply" algorithm which I showed for data_r.
The question is, how can I undo sort on the data_r array?
Either don't sort it at all, and just make a copy of it which gets sorted (or do nothing at all).
Or use the sort_order to reverse it. You just would need to swap i and newIndex (sortOrder[i]) everywhere. Example for building a new, "unsorted" (old-order) array:
var unsorted = new Array(l);
for (var i=0; i<l; i++)
unsorted[i] = data_r[ sort_order[i] ]; // take it from its new position
While this question is 8 years old at this point, I came across it when trying to find the same solution to the problem and I was unable to find a suitable, performant, and intuitive way of doing so, so I wrote one myself.
Please take a look at the sort-unwind library. If ranks is a list of indexes that would rank an array in order...
import unwind from 'sort-unwind'
const suits = ['♥', '♠', '♣', '♦']
const ranks = [2, 0, 3, 1]
const [sortedSuits, tenet] = unwind(ranks, suits)
// sortedSuits <- ['♠', '♦', '♥', '♣']
// unwind <- [1, 3, 0, 2]
You can then use the tenet variable that's returned to unsort an array and restore the original ordering.
const names = ['spades', 'diamonds', 'hearts', 'clubs']
const [tenetNames, tenetRanks] = unwind(tenet, names)
// tenetNames <- ['hearts', 'spades', 'clubs', 'diamonds']
// tenetRanks <- [2, 0, 3, 1]
The sort function just returns a number which can be positive,zero, or negative telling it if the current element goes before,has same weight, or goes after the element it is comparing it too. I would imagine your sort order array is longer than your data_r array because of the number of comparisons you make. I would just make a copy of data_r before you sort it and then set data_r equal to that array when you want it unsorted.
If you have a lot of these arrays to maintain, it might be as well to
convert array1 into an array of objects, each one containing the value
and its original position in the array. This keeps everything together
in one array.
var array1 = [9, 5, 3, 0, 2];
var array2 = ["home", "car", "train", "pc", "mouse"];
var sort = function(array){
var indexed_objects = array.map(function(value, index){
return {index: index, value: value};
});
indexed_objects.sort(function(a,b){
return a.value <= b.value ? -1 : 1;
});
return indexed_objects;
};
var sorted1 = sort(array1);
sorted1; // [{index: 3, value:0}, {index: 4, value: 2}, ...]
And now, given an array of sorted objects, we can write a function to
unsort any other array accordingly:
var unsort = function(array, sorted_objects){
var unsorted = [];
sorted_objects.forEach(function(item, index){
unsorted[item.index] = array[index];
});
return unsorted;
};
var array2_unsorted = unsort(array2, sorted1);
array2_unsorted; // ["mouse", "pc", "train", "home", "car"]
v1 = [0,1,2,3,4,5,6]
q = v1.length
b = []
for(i=0;i<q;i++){
r = parseInt(Math.random()*v1.length)
b.push(v1[r])
a = v1.indexOf(v1[r])
v1.splice(a,1)
}

Find a pair of elements from an given array whose sum equals a specific target number in JavaScript

In Javascript is any other efficient way to achieve this task?
I tried as:
const a1 = [1,3,4,2,5,7,8,6];
var newArray =[];
function fun(a,n){
for(let i = 0; i<a.length; i++){
for(let j=i+1; j<a.length; j++){
if((a[i]+a[j])==n){
newArray.push([a[i],a[j]]);
}
}
}
}
fun(a1, 10)
console.log(newArray);
Here output:
[(3,7),(4,6),(2,8)]
The question is tagged javascript, but this answer is basically language agnostic.
If the array is sorted (or you can sort it), you can iterate over the array and for each element x in it binary search for (target-x) in the array. This gives you O(nlogn) run time.
If you can use extra memory, you can populate a dictionary with the elements of the array, and then for each element x in the array, look up the dictionary for (target-x). If your dictionary is implemented on a hashtable, this gives you O(n) run time.
I think your method makes sense from a brute force perspective.
In terms of optimization, a few things come to mind.
Do duplicates count? If not, you can remove all duplicates from
the starting lists.
You can sort the lists in ascending order,
and skip the remainder of the inner loop when the sum exceeds the
target value.
This is a general programming problem commonly referred to as the "two sum problem", which itself is a subset of the subset sum problem.
But nevertheless can be solved efficiently and I used this article as inspiration.
const a1 = [1, 3, 4, 2, 5, 7, 8, 6];
// our two sum function which will return
// all pairs in the array that sum up to S
function twoSum(arr, S) {
const sums = [];
const hashMap = new Map();
// check each element in array
for (let i = 0; i < arr.length; i++) {
// calculate S - current element
let sumMinusElement = S - arr[i];
// check if this number exists in hash map
// if so then we found a pair of numbers that sum to S
if (hashMap.has(sumMinusElement.toString())) {
sums.push([arr[i], sumMinusElement]);
}
// add the current number to the hash map
hashMap.set(arr[i].toString(), arr[i])
}
// return all pairs of integers that sum to S
return sums;
}
console.log(twoSum(a1, 10))
Here I use the Map object since I think it's faster when checking if number already exists, but I might be wrong and you can use just a plain object, as in the article, if you want.

Categories

Resources