Add a random and not existing item to array from another array - javascript

Let's assume we have an array of items:
const arr1 = [22, 54, 67, 11, ...so on]
and empty one:
let arr2 = []
I can add random item with:
arr2 = [...arr2, arr1[Math.floor(Math.random()*arr1.length)]]
BUT how can I add a random item from first array to 2nd and already added should not be added?
Yes, we can keep added indexes in some tmp variable, but it doesnt seems right and I think there should be a different solution.
NOTE: array spreads because I need to add an item with some events.
For example user click to button and new item will be added to 2nd array, and this array may contain already added elems

You can create your custom logic to push the random value in arr2 so that the condition is that the numbers must be unique in arr2 and it will have maximum random numbers till the length of arr1:
const arr1 = [27, 54, 67, 11, 15, 22, 26, 58, 45, 87];
let arr2 = [];
function getRandom(){
var randomNumber = arr1[Math.floor(Math.random()*arr1.length)];
while(arr2.indexOf(randomNumber) !== -1 && arr2.length !== arr1.length) {
randomNumber = arr1[Math.floor(Math.random()*arr1.length)];
}
arr2.push(randomNumber);
}
getRandom(); getRandom(); getRandom(); getRandom(); getRandom(); getRandom(); getRandom(); getRandom(); getRandom(); getRandom();getRandom();
console.log(arr2);

I think you are looking for something like this:
const arr1 = [22, 54, 67, 11, 23, 56, 43, 77, 34, 76, 30]
let arr2 = []
function addRandom() {
if(new Set(arr1).size === arr2.length) return; //prevention from infinite loop
// if(arr1.length=== arr2.length) return; // if arr1 doesn't contain duplicates
let random = arr1[Math.floor(Math.random()*arr1.length)];
if (!arr2.includes(random)) {
arr2.push(random);
} else {
addRandom();
}
}
addRandom();
console.log(arr2);
addRandom();
console.log(arr2);
addRandom();
console.log(arr2);
If you are sure that arr1 wont contain duplicates then replace (new Set(arr1).size === arr2.length) with arr1.length=== arr2.length.

If this is ok to mutate arr1 (as Matt Burland suggested in comments), try this:
arr2 = [...arr2, ...arr1.splice(Math.floor(Math.random()*arr1.length), 1]);
splice will remove the item from arr1 and return you the item removed, ready to be added in arr2!
If you cannot change it, just make a clone before using this line!
Hoping this will help you :)

If compatibility is not an issue you can use array set.
var arr1 = [44, 55, 100];
var arr2 = [44, 55, 100];
var arr3 = [...new Set(arr1, arr2)];

Something like this should work
let arr1 = [22,43,67,11,63];
let indexes = [...arr1.keys()];
indexes = indexes.sort(() => Math.Random() - 0.5);
let arr2 = [];
arr2 = [...arr2, arr1[indexes.pop()]]
This lets you preserve the original order of your first array too.

You could use the include function on your second array and check if the element you are trying to add does not exists.
let randomItem = arr1[Math.floor(Math.random()*arr1.length)];
while(arra2.includes(randomItem)) {
randomItem = arr1[Math.floor(Math.random()*arr1.length)];
}
arr2.push(randomItem);

#WebArtisan, you can also try the below code.
// Function that returns a randomly selected unique list of items from another
// array with duplicated items
function getUniqueRandomItems(arr1) {
let arr2 = [];
while(arr1.length) {
// A random number in range [0, arr1.length-1]
randomIndex = Math.floor((Math.random() * (arr1.length)) + 1) - 1;
// Removing 1 item from random index in range
removedItem = arr1.splice(randomIndex, 1)[0];
// If removedItem does not exist then add it to arr1
if(arr2.indexOf(removedItem) < 0) {
arr2.push(removedItem);
}
}
return arr2 // Return the result array with unique random items
}
/************ TEST 1****************************************/
const arr1 = [22, 54, 67, 11, 54, 22, 67, 11, 88, 90, 54, 2, 3, 2, 11, 54, 0];
const arr2 = getUniqueRandomItems(arr1);
console.log(arr2); // [ 2, 22, 88, 67, 54, 11, 3, 90, 0 ]
/************ TEST 2****************************************/
const arr3 = [1, 5, 2, 5, 1, 3, 3, 6, 3, 1, 9, 8, 10, 9, 7, 4, 3, 4, 2, 1, 10];
const arr4 = getUniqueRandomItems(arr3);
console.log(arr4); // [ 1, 7, 9, 10, 5, 3, 2, 8, 4, 6 ]

Related

Sorting an array by their ascending value within the array in JS

It's a bit of a tricky situation I'm in, but I have an array like this:
const nums = [32, -3, 62, 8, 121, -231, 62, 13];
and need to replace them by their corresponding ascending index. The above example should yield:
[4, 1, 5, 2, 7, 0, 6, 3]
The solution I've come up with is this: TS Playground
const nums = [32, -3, 62, 8, 121, -231, 62, 13];
const numsCopy = nums.map(e => e);
// Basic sorting
for (let i = 0; i < numsCopy.length; i++) {
for (let j = 0; j < numsCopy.length; j++) {
if (numsCopy[i] < numsCopy[j]) {
let t = numsCopy[j];
numsCopy[j] = numsCopy[i];
numsCopy[i] = t;
}
}
}
for (let i = 0; i < numsCopy.length; i++) {
let sortedValue = numsCopy[i];
nums[nums.indexOf(sortedValue)] = i;
}
Problems arise however when I change nums to include a value nums.length > n >= 0. The call nums.indexOf(...) may return a faulty result, as it may have already sorted an index, even though it exists somewhere in the array.
If you replace nums with these values, -231 will have an index of 2 for some reason...
const nums = [32, -3, 62, 7, 121, -231, 62, 13, 0];
> [5, 1, 6, 3, 8, 2, 7, 4, 0]
Is there a better approach to this problem, or a fix to my solution?
You could sort the indices by the value and create a new array with index values a sorted positions.
to get the wanted result call the sorting function again and you get the indices sorted by the index order.
const
sort = array => [...array.keys()].sort((a, b) => array[a] - array[b]),
fn = array => sort(sort(array));
console.log(...fn([32, -3, 62, 8, 121, -231, 62, 13])); // 4 1 5 2 7 0 6 3
console.log(...fn([-1, 3, 1, 0, 2, 9, -2, 7])); // 1 5 3 2 4 7 0 6
Copy the array, sort its values, get indexOf, and null the value in the sorted copy:
const sortIndicesByValue = array => {
const sorted = [...array].sort((a, b) => a - b);
return array.map(e => {
const i = sorted.indexOf(e);
sorted[i] = null;
return i;
})
}
console.log(...sortIndicesByValue([32, -3, 62, 8, 121, -231, 62, 13]));
console.log(...sortIndicesByValue([-1, 3, 0, 0, 2, 9, -2, 7]));

Javascript sort an array by biggest and lowest number [duplicate]

This question already has answers here:
JavaScript: Rearrange an array in order – largest, smallest, 2nd largest, 2nd smallest, 3rd largest, 3rd smallest,
(4 answers)
Closed 2 years ago.
I need help with the sorting as i am totally confused what to do. This is the example:
[1, 65, 3, 52, 48, 63, 31, -3, 18, 56] to [-3, 65, 1, 63, 3, 56, 18, 52, 31, 48].
The first element has to be the smallest, the second to be biggest, the third to be the second smallest element, the fourth to be the second biggest element.
What i have tried is:
function solve(arr) {
var lowestNum = [...arr].sort((a,b) => a-b);
let biggestNum = [...arr].sort((a,b) => b-a);
let nums = [];
let i = 0;
while (nums.length !== arr.length) {
nums.push(lowestNum.shift()); lowestNum.pop();
nums.push(biggestNum.shift()); biggestNum.pop();
i++;
}
return nums;
}
console.log(solve([1, 65, 3, 52, 48, 63, 31, -3, 18, 56]));
However, that is not the way as my exercise requires me to sort.
This isnt the most elegant solution, but:
let a = [11, 2, 3, -22, 41];
function bigSmallSorter(arr) {
// Sort a copy of the passed in array from least to most.
let sortedArr = [...arr.sort((n, k) => n - k)];
let newArr = [];
let flip = true;
for( let i of arr ) {
let temp = flip
// Take first element of the sorted array
? sortedArr.shift()
// Take the last element of the sorted array
: sortedArr.pop();
// Add the newest value to the value that is ultimately returned
newArr.push(temp);
// Flip this so the next iteration takes from the other
// end of the array
flip = !flip;
}
// Profit
return newArr;
}
console.log(bigSmallSorter(a))
//>[ -22, 41, 2, 11, 3 ]
And an version of the method without comments:
let a = [11, 2, 3, -22, 41];
function bigSmallSorter(arr) {
let sortedArr = [...arr.sort((n, k) => n - k)]
let newArr = [];
let flip = true;
for( let i of arr ) {
let temp = flip
? sortedArr.shift()
: sortedArr.pop()
newArr.push(temp)
flip = !flip;
}
return newArr;
}
console.log(bigSmallSorter(a))

Delete numbers below a certain number in an array

Today i'm facing a really weird problem.
I'm actually trying to delete numbers below a certain number in an array.
I have this array [1, 7, 2, 3, 90, 4, 70, 20] and I only want the numbers greater than 20 !
So I should have that in output : [90, 70]
But Instead I have this array : [7, 3, 90, 70, 20] ???
Here is my code :
function superior() {
var arr = [1, 7, 2, 3, 90, 4, 70, 20]
for (var i = 0; i < arr.length; i++) {
if (arr[i] < 20) {
arr.splice(arr.indexOf(arr[i]), 1);
} else {
break;
}
}
return arr;
}
console.log(superior());
Mutating an array while you're looping through it is always going to be tricky. If you shrink the size of the array, but don't change i, then you're can end up interacting with the wrong element of the array the next time through the loop. Also, using break will stop the loop from running entirely, and so skip the rest of the array. You may have meant to use continue, but since you're on the last line of the loop anyway, continue isn't needed.
Rather than trying to change the array and loop through it at the same time, i'd recommend creating a new array. Then you can loop through the old one unhindered:
const arr = [1, 7, 2, 3, 90, 4, 70, 20]
const newArr = []
for (const i = 0; i < arr.length; i++) {
if (arr[i] >= 20) {
newArr.push(arr[i]);
}
}
console.log(newArr)
Filtering an array like this is a very common thing to do, so there are built in tools to do it for you. Every array has a .filter method. You pass into it a function describing what elements you want to keep, and it will produce the new array for you:
const arr = [1, 7, 2, 3, 90, 4, 70, 20]
const newArr = arr.filter(element => element >= 20);
console.log(newArr)
You can filter them out according to a condition.
And replace your existing array with the filtered one. Or if you don't want to replace it, use another variable and assign the filtered value to that variable.
var newArray = array.filter(item => item > 20)
Check .filter()
var array = [1, 7, 2, 3, 90, 4, 70, 20];
array = array.filter(item => item > 20)
console.log(array)
You can use Array.filter()
var arr = [1, 7, 2, 3, 90, 4, 70, 20]
var filteredArr = arr.filter(item => item > 20);
console.log(filteredArr);
You could iterate from the end and omit indexOf, because you have already the index i.
This appoach loops from the end and after splicing, the remaining lower indices remains.
function superior() {
var array = [1, 7, 2, 3, 90, 4, 70, 20],
i = array.length;
while (i--) if (array[i] < 20) array.splice(i, 1);
return array;
}
console.log(superior());
Use temporary array to push new values.
function superior() {
var arr = [1, 7, 2, 3, 90, 4, 70, 20];
temp_arr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] > 20) {
temp_arr.push(arr[i]);
}
}
return temp_arr;
}
console.log(superior());

Create a New Index Array

Not sure why this isn't working.
Instructions:
// Create a function called indexFinder that will loop over an array and return a new array of the indexes of the contents e.g. [243, 123, 4, 12] would return [0,1,2,3]. Create a new variable called 'indexes' and set it to contain the indexes of randomNumbers.
Tried Solution:
let randomNumbers = [1, 3453, 34, 456, 32, 3, 2, 0];
let indexes = [];
function indexFinder(arr){
for(var i = 0; arr.length; i++){
indexes.push(i);
}
return indexes;
}
indexFinder(randomNumbers);
console.log(indexes);
You have no real condition test in your for loop because arr.length, when above 0, is always truthy.
let randomNumbers = [1, 3453, 34, 456, 32, 3, 2, 0];
let indexes = [];
function indexFinder(arr){
for(var i = 0; i < arr.length; i++){
indexes.push(i);
}
return indexes;
}
indexFinder(randomNumbers);
console.log(indexes);
But there's a much more concise way of doing this:
const randomNumbers = [1, 3453, 34, 456, 32, 3, 2, 0];
const indexFinder = arr => arr.map((_, i) => i);
console.log(indexFinder(randomNumbers));
Another method is using Array.from
const randomNumbers = [1, 3453, 34, 456, 32, 3, 2, 0];
console.log(Array.from(randomNumbers, x => randomNumbers.indexOf(x)));
Or we can use keys
const randomNumbers = [1, 3453, 34, 456, 32, 3, 2, 0];
console.log([...Array(randomNumbers.length).keys()])
The problem is the condition within that for-loop using just arr.length because for length greater than 0 will be always true.
An alternative is using the function Array.from:
let randomNumbers = [1, 3453, 34, 456, 32, 3, 2, 0],
indexes = Array.from({length: randomNumbers.length}, (_, i) => i);
console.log(indexes);
Another alternative is getting the length and then execute a simple for-loop.

Common values in multiple variable lenght javascript arrays

I have 7 arrays in javascript and I need to find values that are present in all of them.
I don't think I'm the first one to ask this but I can't find a solution for this. I read many answers but they all compare only 2 arrays and that logic don't work for multiple arrays.
I tried functions proposed in Simplest code for array intersection in javascript but they don't fit the kind of arrays I have.
The arrays I have can have different lengths in elements and the element's lengtt can vary too. I also may have zero item arrays in which they should not be compared against.
The main problem is with different number lengths. All functions I tried require sorting but this causes a problem.
Given this arrays:
xnombre = [1,2,3,4,5,24,44,124,125,165];
xacomp = [1,5,44,55,124];
xeje = [];
xanio = [1,5,44,55,124];
xini = [1,5,44,55,124];
xaporte = [1,5,44,55,122,123,124,144,155,166,245];
xpcia = [2,1,3,4,6,5,7,9,12,12,14,15,44,16,17,19,124];
The first to arrays are sorted to:
[1, 124, 125, 165, 2, 24, 3, 4, 44, 5]
[1, 124, 44, 5, 55]
Which when I "intersect" I only get [1,124] but 44 and 5 are missed.
Any help would be appreciated.
Thanks
The function from the other question works, but you have to sort your array numerically, not lexicographically, since you are working with numbers, not strings.
function sortNumber(a,b) {
return a - b;
}
var xnombre = [1,2,3,4,5,24,44,124,125,165];
var xacomp = [1,5,44,55,124];
xnombre.sort(sortNumber);
xacomp.sort(sortNumber);
DEMO
To apply this to multiple arrays, you could apply this function consecutively:
// var result = intersect(a, b, c, ...);
function intersect(var_args) {
// sort arrays here or beforehand
var target = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i].length > 0) {
target = intersection_safe(target, arguments[i]);
}
}
return target;
}
This requires some of the new array methods, but it produces your desired output.
function intersection() {
var arrs = Array.prototype.filter.call(arguments, function (a) {
return a.length > 0;
}).sort(function (a, b) { // sort the arrays, so that we test the shortest.
return a.length - b.length;
});
var rest = arrs.slice(1),
test = arrs[0];
return test.filter(function (x) { return rest.every(function (a) { return a.indexOf(x) !== -1; }); });
}
var xnombre = [1, 2, 3, 4, 5, 24, 44, 124, 125, 165],
xacomp = [1, 5, 44, 55, 124],
xeje = [],
xanio = [1, 5, 44, 55, 124],
xini = [1, 5, 44, 55, 124],
xaporte = [1, 5, 44, 55, 122, 123, 124, 144, 155, 166, 245],
xpcia = [2, 1, 3, 4, 6, 5, 7, 9, 12, 12, 14, 15, 44, 16, 17, 19, 124];
intersection(xnombre, xacomp, xeje, xanio, xini, xaporte, xpcia)
// => [1, 5, 44, 124]
I tried your problem with underscore.
var _ = require('underscore');
xnombre = [1,2,3,4,5,24,44,124,125,165];
xacomp = [1,5,44,55,124];
xeje = [];
xanio = [1,5,44,55,124];
xini = [1,5,44,55,124];
xaporte = [1,5,44,55,122,123,124,144,155,166,245];
xpcia = [2,1,3,4,6,5,7,9,12,12,14,15,44,16,17,19,124];
var result = _.intersection(xnombre,xacomp,xanio,xini,xaporte,xpcia);
console.log(result);
But as you see that I haven't given the empty array, so somehow you have to ignore empty array.
Fiddle

Categories