I've got two arrays, numbers and picks. numbers contains a series of numbers, and picks is currently empty. I want to pull N values out of numbers, and put them in picks. So I've tried picks.push(numbers.splice(idx,1));, where idx is a random number between 0 and the highest index in numbers. This doesn't seem to be working. Any advice would be appreciated.
Since splice returns an array, you only need a small tweak, to retrieve the first (and only) item in this new array:
picks.push(numbers.splice(idx,1)[0]);
Well, as many others said, Array.splice() returns an array (with the elements ordered to remove from the source array). So you can either use the fact that you always take a single number from it, as in #JoeEnos answer, or employ more universal form:
[].push.apply(picks, number.splice(idx, 1));
// replace 1 with any other positive number, and it still works
Still, it looks to me you're just trying to reimplement Fisher-Yates shuffle algorithm. Here, the key is using not splice (as reordering huge arrays might cause a performance hit), but exchange the chosen element with the one at the end of the source array. Here's how it can be done:
var source = [1,2,3,4,5,6,7,8];
var shuffled = Array(source.length);
var i, j, len;
for (i = 0, len = shuffled.length; i < len; ++i) {
j = Math.random() * (i + 1)|0;
if (i !== j) {
shuffled[i] = shuffled[j];
}
shuffled[j] = source[i];
}
console.log(shuffled);
Here's eval.in demo to play with.
Related
After I complete a Leetcode question, I always try to also determine the asymptotic time complexity, for practice.
I am now looking at problem 26. Remove Duplicates from Sorted Array:
Given a sorted array nums, remove the duplicates in-place such that
each element appears only once and returns the new length.
Do not allocate extra space for another array, you must do this by
modifying the input array in-place with O(1) extra memory.
Clarification:
Confused why the returned value is an integer but your answer is an
array?
Note that the input array is passed in by reference, which means a
modification to the input array will be known to the caller as well.
Internally you can think of this:
// nums is passed in by reference. (i.e., without making a copy) int
len = removeDuplicates(nums);
// any modification to nums in your function would be known by the caller.
// using the length returned by your function, it prints the first len elements.
for (int i = 0; i < len; i++) {
print(nums[i]);
}
Example 1:
Input: nums = [1,1,2]
Output: 2, nums = [1,2]
Explanation: Your
function should return length = 2, with the first two elements of nums
being 1 and 2 respectively. It doesn't matter what you leave beyond
the returned length.
My code:
/**
* #param {number[]} nums
* #return {number}
*/
var removeDuplicates = function(nums) {
nums.forEach((num,i) => {
if(nums[i+1] !== null && nums[i+1] == nums[i] ){
nums.splice(i, 1);
console.log(nums)
removeDuplicates(nums)
}
})
return nums.length;
};
For this problem, I got O(log n) from my research. Execution time halves each time it runs. Can someone please verify or determine if I am wrong?
Are all recursive functions inherently O(logn)? Even if there are multiple loops?
For this problem, I got O(log n) from my research. Execution time halves for each time it's run. Can someone please verify or determine if I am wrong?
The execution time does not halve for each run: imagine an extreme case where the input has 100 values and they are all the same. Then at each level of the recursion tree one of those duplicates will be found and removed. Then a deeper recursive call is made. So for every duplicate value there is a level in the recursion tree. So in this extreme case, the recursion tree will have a depth of 99.
Even if you would revise the algorithm, it would not be possible to make it O(log n), as all values in the array need to be read at least once, and that alone already gives it a time complexity of O(n).
Your implementation uses splice which needs to shift all the values that follow the deletion point, so one splice is already O(n), making your algorithm O(n²) (worst case).
Because of the recursion, it also uses O(n) extra space in the worst case (for the call stack).
Are all recursive functions inherently O(logn)?
No. Using recursion does not say anything about the overall time complexity. It could be anything. You typically get O(logn) when you can ignore O(n) (like half) of the current array when making the recursive call. This is for instance the case with a Binary Search algorithm.
Improvement
You can avoid the extra space by not using recursion, but an iterative method. Also, you are not required to actually change the length of the given array, only to return what its new length should be. So you can avoid using splice. Instead, use two indexes in the array: one that runs to the next character that is different, and another, a slower one, to which you copy that new character. When the faster index reaches the end of the input, the slower one indicates the size of the part that has the unique values.
Here is how that looks:
var removeDuplicates = function(nums) {
if (nums.length == 0) return 0;
let len = 1;
for (let j = 1; j < nums.length; j++) {
if (nums[j-1] !== nums[j]) nums[len++] = nums[j];
}
return len;
};
I'm currently doing an assignment for school and could really use your help.
I have to declare a function which takes two arguments, x and an array, arr. It has to return an array which contains multiple arrays with x inserted into respectively index 0 in the first array, index 1 in the second array and so on until there's no more numbers in the array. See picture of an example and for clarification of what the final result is expected to look like. It has to work on any given array and the assignment specifies that slice() and concat() would be good to use. example of assignment
function insert_all_positions (x, arr) {
var newArr = [];
for(var i = 0; i < arr.length; i++) {
return(arr.concat(x)); }
};
This just adds the x-value to the end of the array and I have to loop it so the value will be inserted at all indexes. I'm thinking the array.splice() method can be used, I'm just not sure how as I'm not particularly experienced with it. Thank you :)
As Nina already said: the idea of assignments is, that you try something yourself which we can then help you to improve.
Nonetheless, here is one simple way of doing what was required:
function iap(v,arr){
var l=arr.length, ret=[];
for (var i=0;i<=l;i++) ret.push(arr.slice(0,i).concat([v],arr.slice(i,l)));
return ret;
}
console.log(iap(8,[1,2,3]));
Try this
function myFunc(x,arr){
let result =[]
for(let i=0;i<arr.length;i++){
let arrToAdd = [...arr]
arrToAdd[i]=x
result.push(arrToAdd)
}
return result
}
You create a result array that you push your arrays into, then you run a loop that will run the exact number of times as the length of your argument arr. Each iteration of the loop creates a new array that is a copy of arr and then you just change one number in it each time and add the entire array to the result.
I can either do,
var arr = [];
arr.forEach(function(i) {
i;
});
for (var i = 0, length = arr.length; i < length; ++i) {
arr[i];
}
When should I use one over the other, is there performance differences?
You use foreach whenever :
your array is associtive or has gaps, i.e. you cannot reach every element by an incremented number (1,2,5, 'x', -7)
you need to iterate in exactly the same order as they appear in the array. (e.g. 2,1,3)
you want to be sure not the get into an endless loop
The last point is the main difference: foreach works on a copy, so even if you alter the elements, the array remains intact and can be iterated without defects.
That copy makes foreach somewhat slower than for, since it has to copy data. Keep in mind that some old or rare browsers don´t supports foreach, but they do support "for". Unless your array is really big (10.000 + items), ignore the speed difference. It´s in the milliseconds.
You use for whenever
you want an easy way to aler the array you are moving on
you want specific sequences, e.g. for ($i=100; $i < 1000; $i += 5) resulting in 100, 105, 110...
I have a set of arrays named in the following fashion: question0, question1, question2 etc.
I also have a variable that corresponds to the question number.
With this, how would I access array question0 without having to type out the whole name. For example, in a for loop, I have if the loop number is 5, I want to do an operation on question5. I know this is really simple, but I haven't been able to find the solution.
Variables ending in sequential numbers are usually a hint to use arrays. Sounds like you need an array of arrays instead, and then you can just:
doOperation(question[somenumber])
Why not just use a big array, question, where each item it itself an array?
That aside, if the variables are global then you could use window['question'+i], with i being the number of the question.
Don't use variable names with an ordinal number as their suffix; use the proper structures, such as an array:
var questions = ['why?', 'what?', 'where?'],
nr = 2; // the question number
alert(questions[nr]);
In my example, each "question" is a string, but it could be any other structure, including another array.
I think it would be simpler to have your question(n) values as an array. From there you could use the following: questions[i] where i represents the current loop number, thus improving manipulation.
var questions = [["What?", "Why?"], ["When?", "How?"]];
for(var i = 0; i < questions.length; i++) {
for(var j = 0; j < questions[i].length; j++) {
console.info(questions[i][j]);
}
}
Are there any performance difference between
var a = [10,20,30,40];// Assume we have thousands of values here
// Approach 1
var i, len = a.length;
for(i=0;i<len;i++){
alert(i);
alert(a[i]);
}
// Approach 2
for( i in a ){
alert(i);
alert(a[i]);
}
Use for (var i = 0, len = a.length; i < len; i++) because it's way faster and it's the correct way or iterating the items in an array.
First: It's not correct to iterate arrays with for (i in a) because that iteration will include enumerable properties in addition to array elements. If any methods or properties have been added to the array, they will be part of the iteration when using for (i in a) which is never what you want when trying to traverse the elements of the array.
Second: The correct option is a lot faster (9-20x faster). See this jsPerf test which shows the for (var i = 0; i < len; i++) option to be about 9x faster in Chrome and even more of a speed difference in Firefox: http://jsperf.com/for-loop-comparison2.
As an example of the problems that can occur when using for (var i in a), when I use that when the mootools library is included in the project, I get all these values for i:
0
1
2
3
$family
$constructor
each
clone
clean
invoke
associate
link
contains
append
getLast
getRandom
include
combine
erase
empty
flatten
pick
hexToRgb
rgbToHex
which appears to be a bunch of methods that mootools has added to the array object.
I don't know across browsers, but in my test with Firefox there is. for (i=0; etc...) is much faster. Here is a jsfiddle example that shows the difference. http://jsfiddle.net/pseudosavant/VyRH3/
Add to that the problems that you can encounter with (for i in etc) when the Array object has been prototype (perhaps in a library), you should always use for (i=0; etc...) for looping over arrays.
(for i in etc) should only ever be used on objects.