What would be the best way to shuffle an array of numbers with the condition that each number must be +3 or -3 of the next/prev number? So, for example [0,1] wouldn't work, but [0,3] would.
Thanks!
Looking at the screenshot it seems you're wanting to pick a random assortment from the list, with no 2 choices being within 3 of each other.
This code takes an array, and gives you a subset of the array satisfying that condition.
You can specify a maximum number of selections too, although you might not always get that many.
var src = [0,1,2,3,4,5,6,7,8,9,10,11,12];
var getRnd = function(max){
var output = [];
var newSrc = src.slice();
var test, index, i, safe;
while (newSrc.length > 0 && output.length < max){
index = Math.floor(Math.random()*newSrc.length);
test = newSrc.splice(index,1);
//Make sure it's not within 3
safe = true;
for (i=0; i<output.length;i++){
if(Math.abs(test-output[i]) < 3){
//abort!
safe=false;
}
}
if(safe){
output.push(test);
}
}
return output;
};
alert(getRnd(4));
A way (likley not the fastes) would be to:
sort array
pick random element to start new shuffled array with (mark element in sorted array as used or remove)
with binary search find next element that is +3 or -3 for the last one (randomly pick between -3 and +3). Make sure element is not marked as used before (otherwise find another one)
repeat 3 till you can find elements.
you either picked all elements from sorted array or such shuffling is not possible.
I think you get O(N*logN) with this (sorting N*logN and picking N elements with logN for each serch).
Assuming that the values in the array cannot be duplicated.
function one(array, mod){
var modArray = [];
for(var index in array){
var item = array[index];
var itemMod = item%3;
if(itemMod === mod){
modArray.push(item);
}
}
return modArray();
}
function two(modArray){
var sortedArray = // sort highest to lowest
for(var index in sortedArray ){
var item = array[index];
if(index > 0 && item[index-1] === item[index]-3){
}else{return false;}
}
return sortedArray.length;
}
function main(array){
var a1 = one(array, 0);
var a2 = one(array, 1);
var a3 = one(array, 2);
var a1c = two(a1);
var a2c = two(a2);
var a3c = two(a3);
return // if a1c is greatest then a1, if a2c greatest then a2 ... etc
}
I think you must be using the phrase "shuffle" in some non-standard way. If all of the numbers are already within +-3 of each other, then sorting the array will put them in the right order, unless there are duplicates, I guess.
More examples would probably be helpful. For instance, are these examples valid, and the sort of thing you're looking for?
[0, 3, 3] -> [3, 0, 3]
[9, 3, 6, 0, 6] -> [0, 3, 6, 9, 6]
[3, 3, 6, 0, 6] -> [0, 3, 6, 3, 6]
It feels like this is probably a solved problem in graph theory - some kind of network traversal with a maximum/minimum cost function.
Related
I need to find the sum of elements from the beginning of the array to the first negative number, using loops, like "for". I want loop to summarize all the elements of array before the first negative number and return the sum.
Like for example if I have:
arr = [1, 2, 3, -4, 5]
I need to summarize all elements before "-4" , output would be
6
to print in the console.
Simply iterate over the numbers and break the loop at the first negative one.
let arr = [1, 2, 3, -4, 5];
let res = 0;
for (const num of arr) {
if (num < 0) break;
res += num;
}
console.log(res);
Given an array of integers, where the values should be sorted in the following order:
if we have an array
[1, -1, -3, 9, -2, -5, 4, 8,]
we must rearrange it this way: largest number, smallest number, 2nd largest number, 2nd smallest number, ...
[9, -5, 8, -3, 4, -2, 1, -1 ]
I get the first largest and smallest numbers, but can't figure out how to make it dynamic for all values in the array.
I know that I must take two variables, say firstSmallest and firstLargest and point them to the first and last index of the array respectively, run a loop, which I do already in the code below, and store value into new array by incrementing firstSmallest and decrementing firstLargest, but couldn't implement into code.
let unsortedArr = [1, 5, 8 , 7, 6, -1, -5, 4, 9, 5]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => a-b);
let firstSmallest = sorted[0];
let firstLargest = sorted[unsorted.length-1];
for(let i = 0; i <= sorted.length; i++){
//I should increment firstSmallest and decrement firstLargest numbers and store in output
}
return output;
}
meanderArray(unsortedArr);
console.log(output);
You could take a toggle object which takes the property of either the first item or last from an array and iterate until no more items are available.
function meanderArray([...array]) {
const
result = [],
toggle = { shift: 'pop', pop: 'shift' };
let fn = 'shift';
array.sort((a, b) => a - b);
while (array.length) result.push(array[fn = toggle[fn]]());
return result;
}
console.log(...meanderArray([1, 5, 8, 7, 6, -1, -5, 4, 9, 5]));
You can sort an array by descending, then logic is the following: take first from start and first from end, then second from start-second from end, etc.
let unsortedArr = [1, 5, 8 , 7, 6, -1, -5, 4, 9, 5]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => b-a);
let output = []
for(let i = 0; i < sorted.length/2; i++){
output.push(sorted[i])
if(i !== sorted.length - 1 - i){
output.push(sorted[sorted.length - 1 - i])
}
}
return output;
}
let result = meanderArray(unsortedArr);
console.log(result);
You can sort, then loop and extract the last number with pop() and extract the first number with shift().
let unsortedArr = [1, -1, -3, 9, -2, -5, 4, 8,]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => a - b);
for(let i = 0; i < unsortedArr.length + 2; i++){
output.push(sorted.pop());
output.push(sorted.shift());
}
console.log(output);
return output;
}
meanderArray(unsortedArr);
Fastest Meandering Array method among all solutions mentioned above.
According to the JSBench.me, this solution is the fastest and for your reference i have attached a screenshot below.
I got a different approach, but i found that was very close to one of above answers from elvira.genkel.
In my solution for Meandering Array, First I sorted the given array and then i tried to find the middle of the array. After that i divided sorted array in to two arrays, which are indices from 0 to middle index and other one is from middle index to full length of sorted array.
We need to make sure that first half of array's length is greater than the second array. Other wise when applying for() loop as next step newly created array will contains some undefined values. For avoiding this issue i have incremented first array length by one.
So, always it should be firstArr.length > secondArr.length.
And planned to create new array with values in meandering order. As next step I created for() loop and try to push values from beginning of the first array and from end of the second array. Make sure that dynamically created index of second array will receive only zero or positive index. Other wise you can find undefined values inside newly created Meandering Array.
Hope this solution will be helpful for everyone, who loves to do high performance coding :)
Your comments and suggestions are welcome.
const unsorted = [1, 5, 8, 7, 6, -1, -5, 4, 9, 5];
const sorted = unsorted.sort((a,b)=>a-b).reverse();
const half = Math.round(Math.floor(sorted.length/2)) + 1;
const leftArr = sorted.slice(0, half);
const rightArr = sorted.slice(half, sorted.length);
const newArr = [];
for(let i=0; i<leftArr.length; i++) {
newArr.push(leftArr[i]);
if (rightArr.length-1-i >= 0) {
newArr.push(rightArr[rightArr.length-1-i]);
}
}
I have a sorted list of numbers. I want to search the array for a number (lets call it searchVal). So the line of code below works fine if the number is in the array.
var sPos = $.inArray(searchVal, MyArray);
However if it is not in MyArray I want to select the next biggest number, i.e
I'm searching for 8 in the list below I would like it to return 10.
4, 5, 6, 10, 11
I am new to javascript and wondering what the best way to achieve this is? I have seen a filter could be used where any number >= to 8 is returned and then take the min number from this filtered list. Or is this a case when I should make use of the reduce function?
You can use Array.find() on sorted array.
The find() method returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.
console.log([13, 4, 6, 5, 10, 11].sort((a, b) => a > b).find(x => x > 8));
Since the array is sorted you can use
var num = MyArray.find(x => x > 8)
For unsorted data, you could take the absolute delta of an item and check with the delta of last item and return the one with smaller delta.
var array = [5, 4, 11, 6, 10],
find = 8,
nearest = array.reduce((a, b) => Math.abs(a - find) < Math.abs(b - find) ? a : b);
console.log(nearest);
Hi you use the map function to determine the distance to 8.
var array = [4, 5, 6, 10, 11];
var distanceArray = array.map(function(element){
var distance = 8-element
if(distance < 0){
distance = distance * -1;
}
return distance;
})
then you got [4,3,2,2,3]. use Math.min
var minimum = Math.min(...distanceArray);
Now you got 2 as minimum. now found the position
var position = distanceArray.indexOf(minimum);
now you can see whats number is nearest,
var nearest = array[position];
got you 6....
I am having trouble with a problem and how to address it. Mind you, I am relatively new to JavaScript and the problem feels like I am over complicating it.
The problem:
Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
Example
For sequence = [1, 3, 2, 1], the output should be
almostIncreasingSequence(sequence) = false;
There is no one element in this array that can be removed in order to get a strictly increasing sequence.
For sequence = [1, 3, 2], the output should be
almostIncreasingSequence(sequence) = true.
You can remove 3 from the array to get the strictly increasing sequence [1, 2]. Alternately, you can remove 2 to get the strictly increasing sequence [1, 3].
Thanks for all your comments! I wanted to update this to be a better question, and also inform you I have found a solution if someone would like to check it and see if there is a cleaner way to put it. :)
function almostIncreasingSequence(sequence) {
if(sequence.length == 2) return true;
var error = 0;
for(var i = 0; i < sequence.length - 1; i++){
if(sequence[i] >= sequence[i+1]){
var noStepBack = sequence[i-1] && sequence[i-1] >= sequence[i+1];
var noStepFoward = sequence[i+2] && sequence[i] >= sequence[i+2];
if(i > 0 && noStepBack && noStepFoward) {
error+=2;
}else{
error++;
}
}
if(error > 1){
return false;
}
}
return true;
}
Think about what your code:
sequence[i+1] - sequence[i] !== 1, variable++;
would do for the following array:[1,2,3,8,8].
From the problem description, it is not clear weather the program must remove one character. But if that is the case, the code below should do it.
function canGetStrictlyIncreasingSeq(numbers) {
var counter = 0;
var lastGreatestNumber = numbers[0];
for (var i = 1; i < numbers.length; i++) {
if (lastGreatestNumber >= numbers[i]) {
counter++;
lastGreatestNumber = numbers[i];
} else {
lastGreatestNumber = numbers[i];
}
}
if (counter <= 1)
return true;
return false;
}
var nums1 = [1, 2, 3, 4, 5]; //true
var nums2 = [1, 2, 2, 3, 4]; //true
var nums3 = [1, 3, 8, 1, 9]; //true
var nums4 = [3, 2, 5, 6, 9]; //true
var nums5 = [3, 2, 1, 0, 5]; //false
var nums6 = [1, 2, 2, 2, 3]; //false
var nums7 = [1, 1, 1, 1, 1]; //false
var nums8 = [1, 2]; //true
var nums9 = [1, 2, 2]; //true
var nums10 = [1, 1, 2, 3, 4, 5, 5]; //false
var nums11 = [10, 1, 2, 3, 4, 5]; //true
var nums12 = [1, 2, 3, 4, 99, 5, 6]; //true
console.log(canGetStrictlyIncreasingSeq(nums1));
console.log(canGetStrictlyIncreasingSeq(nums2));
console.log(canGetStrictlyIncreasingSeq(nums3));
console.log(canGetStrictlyIncreasingSeq(nums4));
console.log(canGetStrictlyIncreasingSeq(nums5));
console.log(canGetStrictlyIncreasingSeq(nums6));
console.log(canGetStrictlyIncreasingSeq(nums7));
console.log(canGetStrictlyIncreasingSeq(nums8));
console.log(canGetStrictlyIncreasingSeq(nums9));
console.log(canGetStrictlyIncreasingSeq(nums10));
console.log(canGetStrictlyIncreasingSeq(nums11));
console.log(canGetStrictlyIncreasingSeq(nums12));
Lets take a step back and think about the problem: "Given a sequence of Integers as an array" - we're dealing with arrays of data...but you already knew that.
"determine whether it is possible to obtain a strictly increasing sequence" ok, we need to make something that checks for valid sequence.
"by removing no more than one element from the array." so we can try plucking each element one-by-one and if at least one resulting array is sequential, its possible.
Now instead of one large problem we have two smaller ones
First, we're dealing with arrays, so avail yourself to JavaScript's built-in Array functions to make things easier. In the below, we use 'every()', 'forEach()', 'splice()', 'push()', and 'some()' You can read into how they work here https://www.w3schools.com/jsref/jsref_obj_array.asp It's not long and well worth your time.
Lets deal with the first problem: Determining if an array is sequential. The below function does this
function checkSequence(inputArray){
return inputArray.every(function(value, index, arr){
if (index == 0 && value < arr[index + 1]) {return true}
else if (index < arr.length && value < arr[index + 1] && value > arr[index - 1]) {return true}
else if (index = arr.length - 1 && value > arr[index - 1]) {return true}
else {return false}
});
}
It takes an input array, and uses an Array built-in function called every(), which runs a test on each element in an array
and returns 'true' if all the elements test true. Our test expects the first element to always be lower less than the second
for any given element to be greater than the previous, and less than the next, and for the last element to be greater than the next-to-last
if any element does not satisfy this test, the whole thing returns false
Now we have a means of seeing of an array is sequential, which will make the next part much easier
Now we make another function to pluck out individual elements and see if anythign works
function isPossible(input){
var results = []; //we will store our future results here
input.forEach(function(value, index, arr){
copy = Array.from(arr); //we work on a copy of 'arr' to avoid messing it up (splice mangles what you give it, and we need the un-maimed version for later iterations)
copy.splice(index, 1); //remove an element from copy (a copy of 'arr')
results.push(checkSequence(copy)); //see if it is still in sequence
});
return results.some(function(value){return value});
}
We first make an array to store the results of each attempt into the array 'results' we will use it later.
Then, we take a supplied array 'input' and use "forEach()", which performs a function with each element in an array.
for each element, we make a new array with that element removed from it, and we run the "checkSequence()"
function we made before on it, and finally store the result in the results array.
When the forEach is done, we take the results array and use 'some()' on it, which works just like 'every()'
only it returns true if at least one value is true
Now, you simply call isPossible(your_array) and it will satisfy the problem
Taking into account Patrick Barr's suggestion and assuming that es6 and arrow functions are fine, this solution using Array.prototype.filter could work. The filter itself will return array of elements that should be removed to satisfy conditions of the problem:
UPDATED
function isSequential(array) {
return array && array.length > 0 ? array.filter((x,i) => x >= array[i + 1] || array[i + 1] <= array[i - 1]).length < 2 : false;
}
console.log(isSequential([1]));
console.log(isSequential([1,2,4,5,6]));
console.log(isSequential([1,2,2,3,4,5,6]));
console.log(isSequential([1,4,3,2,5,6]));
console.log(isSequential([1,2,3,4,5,6]));
console.log(isSequential([1,2,0,3,4]));
console.log(isSequential([1,1]));
console.log(isSequential([1,2,0,1,2]));
console.log(isSequential([1,2,3,1,2,3]));
console.log(isSequential([]));
console.log(isSequential([1,0,0,1]));
console.log(isSequential([1,2,6,3,4])); //should be true, but return false
I was trying to solve some of the programming challenges at "free code camp" website, The problem was to find the symmetric difference between multiple arrays and returning an array of the symmetric difference of the provided arrays.
for example the following arrays:
[1, 2, 5], [2, 3, 5], [3, 4, 5]
should return [ 1, 4, 5 ]
so that's what I came up with:
function sym() {
var final = [];
var current_array = [];
for (var i = 0; i < arguments.length; i++) {
current_array = arguments[i];
//ensures duplicates inside each array are removed first
current_array = current_array.filter(function (element, index) {
return current_array.indexOf(element) == index;
});
for (var j = 0, end = current_array.length; j < end; j++) {
if(final.indexOf(current_array[j]) < 0)
final.push(current_array[j]);
else
// for some reason "splice" isn't working properly..
// final.splice(final.indexOf(current_array[j], 1));
delete final[final.indexOf(current_array[j])];
}
}
var final_2 = [];
// Removing the empty slots caused by the "delete" keyword usage
for (var m = 0; m < final.length; m++) {
if(typeof final[m] !== 'undefined')
final_2.push(final[m]);
}
return final_2;
}
in the previous logic I created an array called final that is supposed to hold all of the elements that only exist once in all of the passed arrays, firstly I loop over the arguments parameter which represents here the arrays and for each array I loop over its elements and check if that element exists in the final array or not. If it exists I remove it from the final array, else I push it to the array.
The problem here is if I use the splice method as given in the code above, it behaves very strangely, for example for the following arrays
[1, 2, 3], [5, 2, 1, 4], the result should be: [3, 5, 4]
when I use this line
final.splice(final.indexOf(current_array[j], 1));
instead of
delete final[final.indexOf(current_array[j])];
and return the final array it returns this [ 4 ]
here is the array values at each iteration
round (0, 0): 1
round (0, 1): 1,2
round (0, 2): 1,2,3
round (1, 0): 1,2,3,5
round (1, 1): 1
round (1, 2):
round (1, 3): 4
once it gets to an element that exists in the array it removes all of the elements starting from this element until the end of the array.
I don't know exactly if I'm missing something, I tried to search for any similar problems but most of what I came up with was a problem of removing elements from an array that the person was looping over and hence missing with its indices .. In my case the array I'm trying to modify got nothing to do with the arrays I'm iterating through.
Also I believe splice modifies the array in place and returns the removed elements.. please correct me if I'm not getting it well.
You've misplaced a ), here's the correction:
final.splice( final.indexOf(current_array[j]), 1 );
An additional note: the algorithm adds 5 for the first array, removes it for the second, and adds it again for the third (since it isn't present in final anymore), resulting in [1,4,5].
With an odd number of arguments, the value is preserved, with an even number, it is removed.
A simpler way to get all unique values from all arrays (if that is the intent), is to count the occurrences and filter on a single occurrence:
function sym2() {
var count = {};
for ( var i in arguments ) {
console.log("Processing ", i );
for ( var k = 0; k < arguments[i].length; k ++)
count[ arguments[i][k] ] = (count[ arguments[i][k] ]||0) + 1;
}
var final = [];
for ( var i in count )
if ( count[i] == 1 )
final.push( i );
return final;
}
sym2([1, 2, 5], [2, 3, 5], [3, 4, 5]);
Note that this will return [1,4] rather than [1,4,5].