I'm trying to implement a recursive permutation generator in Javascript, but I can't seem to get it to go through all the recursion branches (see the Results below).
I know I'm missing something important, can someone help me understand where I've gone wrong?
var permute = function(input){
var permutation = function (arr, position){
if(position >= arr.length-1){
results.push(arr);
}else{
var tempSwap="";
for(i=position;i<arr.length;i++){
tempSwap = arr[position];
arr.splice(position,1,arr[i]);
arr.splice(i,1,tempSwap);
permutation(arr,(position+1));
}
return;
}
};
permutation(input,0);
};
var results=[];
permute(['a','b','c']);
console.log(results);
Results:
[ [ 'a', 'c', 'b' ], [ 'a', 'c', 'b' ] ]
There were two errors: you was working on the same array without making copies and your loop counter i was a global variable. Fixed code:
var permute = function(input){
var permutation = function (arr, position){
if(position == arr.length-1){ // >= was redundant and confusing
results.push(arr);
}else{
for(var i=position;i<arr.length;i++){ // use local i
var tempSwap = arr[position];
arr.splice(position,1,arr[i]);
arr.splice(i,1,tempSwap);
permutation(arr.slice(),(position+1)); // you need a copy here
}
return;
}
};
permutation(input,0);
};
var results=[];
permute(['a','b','c']);
console.log(results.join(' ')); // a,b,c a,c,b b,a,c b,c,a c,a,b c,b,a
https://jsfiddle.net/sagqkchL/1/
Not making copies caused all of your result arrays to look the same. The global variable caused only 2 results being produced.
I know I'm missing important
Your i variable is implictly global. Declare it with var, and your basic problem will go away.
Also, as mentioned in the comments, you are not copying the input array so you're always modifying the same object (and end up with result[0] == result[1] == …); you end your recursion one level too early (the base case is when you've met the end, not before); and also you should create the results array within the permute function.
function permute(input){
function permutation(arr, position){
if(position >= arr.length) {
results.push(arr);
} else {
permutation(arr, position+1); // nothing is swapped, no need to copy anything
// you can also omit this line and start i=position
for (var i=position+1; i<arr.length; i++) {
var tmp = arr.slice();
tmp[position] = arr[i];
tmp[i] = arr[position];
permutation(tmp, position+1);
}
}
};
var results = [];
permutation(input, 0);
return results;
};
console.log(permute(['a','b','c'])); // [["a","b","c"],["a","c","b"],["b","a","c"],["b","c","a"],["c","b","a"],["c","a","b"]]
Related
Hi I'm trying to learn how to implement callback functions. My teacher has helped me out multiple times but I still can't pass data through the following equation below. I'm trying to get certain elements of array to get pushed into a new function if only they pass a test within the function. Please have a look and thank you for your input. An explanation as to why I get an empty array and resources to further my understanding would be appreciated.
// EACH DEFINITION
function each (collection, callback) {
for(var i = 0; i < collection.length; i ++){
callback(collection[i]);
}
}
// VARIABLE DECLARATION
var myArray = [1,2,3,4,5,6];
var isEven = function (num) {
return num % 2 === 0;
};
// IMPLEMENT DEFINITION
function implement(array, test){ // array = myArray, test = isEven
var arr = [];
each(array, function(item){
test(item);
});
if(test(array)){
arr.push(array);
}
return arr;
}
// IMPLEMENT INVOCATION
implement(myArray, isEven);
You are building arr outside the each() loop.
I would think your code would be like this:
// IMPLEMENT DEFINITION
function implement(array, test){ // array = myArray, test = isEven
var arr = [];
each(array, function(item){
if(test(item)) {
arr.push(item);
}
});
return arr;
}
Though in this case there is no reason for your implement() filtering function at all, since javascript Array prototype already has a filter method. You could simplify your call to this:
var filteredArray = myArray.filter(isEven);
Though you might also then want to change your isEven definition to be more correct as:
var isEven = function (num, index, array) {
In your case you don't need to work with the last two parameters.
// EACH DEFINITION
function each (collection, callback, results) {
for(var i = 0; i < collection.length; i ++){
callback(collection[i]);
}
console.log(results);
}
// VARIABLE DECLARATION
var myArray = [1,2,3,4,5,6];
var isEven = function (num, array) {
return num % 2 === 0;
};
// IMPLEMENT DEFINITION
function implement(array, test){ // array = myArray, test = isEven
var arr = [];
function filter (item) {
if (test(item)) {
arr.push(item);
}
}
each(array, filter, arr);
// If you return arr here, it will still be empty. You must pass it to functions it is being operated on.
}
// IMPLEMENT INVOCATION
implement(myArray, isEven);
Not only are you trying to push to arr outside of your loop, but you're trying to return arr before it has gained any values.
Two points:
First, your implementation of callback functions is correct. As far as the concept of callbacks goes, you are calling and passing the functions correctly.
However, your implement() function probably has a bug. You are not pushing to arr until after each() has already been called:
function implement(array, test) { // array = myArray, test = isEven
var arr = [];
each(array, function(item) {
result = test(item);
});
// This block should be in the loop itself
// It should also refer to item, not array
if (test(array)) {
arr.push(array);
}
return arr;
}
Try this fix based on the code you provided:
// EACH DEFINITION
function each(collection, callback) {
for (var i = 0; i < collection.length; i++) {
callback(collection[i]);
}
}
// VARIABLE DECLARATION
var myArray = [1, 2, 3, 4, 5, 6];
var isEven = function(num) {
return num % 2 === 0;
};
// IMPLEMENT DEFINITION
function implement(array, test) { // array = myArray, test = isEven
var arr = [];
each(array, function(item) {
if (test(item)) {
arr.push(item)
}
});
if (test(array)) {
arr.push(array);
}
return arr;
}
// IMPLEMENT INVOCATION
var result = implement(myArray, isEven);
console.log(result); // For snippet results
Your callback, as you defined it, is
function(item){
test(item);
}
this will only call test on each item and that's it. Since you want to take it further and add item to arr if test returns true, you should put that checking code inside the callback as well, making it
function(item){
if (test(item)) {
arr.push(item);
}
}
so that this function will be called for each of the item.
Also, this part
if(test(array)){
arr.push(array);
}
is incorrect because you are passing a whole array into isEven when isEven is expecting a number. test(array) will always return false; that's why your arr is empty.
Modifying your code to work as you wanted, it would be
// IMPLEMENT DEFINITION
function implement(array, test){ // array = myArray, test = isEven
var arr = [];
each(array, function(item){
if (test(item)) {
arr.push(item);
}
});
return arr;
}
Resources wise, there are callbacks tutorial widely available online, as well as best practices. You can easily find one that suits you best by googling.
It looks to me like the entire issue here is in the implementation section you denote. All of the other code looks adequate.
each(array, function(item){
test(item);
});
Alright, first let's examine this piece of code. You are making a call to your each function, which will use the callback anonymous function defined here as shown.
However, if you were to look at the each function itself, there is no return (which means it returns undefined by default). There is also no modification being done in each. As a result, this set of code has no effect on the execution of the code, and from certain advanced compilation technique may actually be removed by the V8 engine in chrome if that was being used.
This means the only aspect of your code which is executing is
var arr = [];
if(test(array)){
arr.push(array);
}
return arr;
At this point, test is still the isEven function, so you are basically asking this
if(array % 2 === 0) arr.push(array);
Arrays in JavaScript behave interestingly when used in conditional statements, and in this situation the array essentially has toString called on it (more in depth here: https://stackoverflow.com/a/10556035/1026459 , but basically when you have object === number then it will attempt to use toPrimitive on the object which results in a string), which makes it
if("1,2,3" % 2 === 0)
which is false. As a result arr is unchanged, and returned in its original state of [].
My main goal for academic purposes is to solve this problem and for the most part I did. Also I wanted to make sure that I was not missing a fundamental part of reduce by not understanding what is wrong with my code.
This is how I would solve it, I've attached my reduce function as well as filter function. I believe my reduce function works however, my filter function isn't quite working so well as I can't pass my test cases.
1) Why am i not hitting the last element of the array?
I've noticed that prev and curr actually never return 5 at any point of the reduce function. Am I missing something in my reduce function?
myArray = [1,2,3,4,5];
function each(collection, action){
if(Array.isArray(collection)){
for(var i = 0; i < collection.length; i ++){
action(collection[i]);
}
}
else if(typeof(collection) === "object"){
for (var property in collection){
action(collection[property]);
}
}
}
function reduce(collection, combine, start){
each(collection, function(element){
if(start === undefined){
return start = element;
}
else {
return start = combine(start, element);
}
});
return start;
}
function filterR(collection, predicate){
var aR = [];
reduce(collection, function(prev, curr){
if(predicate(prev)){
aR.push(prev);
}
if(predicate(curr)){
aR.push(curr);
}
});
return aR;
}
console.log(filter(myArray, function(val){return val % 5 === 0;})); //expected [5]
console.log(filter(myArray, function(val){return val <= 5;})); //expected [1,2,3,4,5]
I can't diagnose your problem because I don't know what your each procedure is.
Anyway, it doesn't matter; you're overthinking it.
reduce is very simple to implement by hand.
function reduce(f, start, arr) {
if (arr.length === 0)
return start;
else
return reduce(f, f(start, arr[0]), arr.slice(1));
}
// example
function add(x,y) { return x+y; }
reduce(add, 0, []); //=> 0
reduce(add, 0, [1,2,3]); //=> 6
I see that you are trying to support a sort of reduce without an optional starting value. That is impossible if your reduce function is to be considered a total function. A starting value is required. Don't try to be clever.
Now a filter implemented using reduce
function filter(f, arr) {
return reduce(function(result, x) {
if (f(x))
return result.concat([x]);
else
return result;
}, [], arr);
}
Your examples
var myArray = [1,2,3,4,5];
filter(function(val){return val % 5 === 0;}, myArray)
//=> [5]
filter(function(val){return val <= 5;}, myArray)
//=> [1, 2, 3, 4, 5]
If you want to learn more...
There are other ways to implement reduce as well. One such improvement you could make is to put the recursion in tail position. When JavaScript engines support tail call elimination (with ES6), this would prevent reduce from stack-overflowing for significantly large values of arr.
function reduce(f, start, arr) {
function loop(result, arr) {
if (arr.length === 0)
return result;
else
return loop(f(result, arr[0]), arr.slice(1));
}
return loop(start, arr);
}
A blackhole appears...
With reduce and higher-order functions under your belt, you now stand at the shores of the deep, vast sea that is lambda calculus and functional programming. If you're feeling very zealous, you can explore how currying and combinators change this definition even more dramatically.
The following code is written in ES6
// U-combinator
const U = f=> f(f);
// Y-combinator
const Y = U (h=> f=> f (x=> h (h) (f) (x)));
// reduce
const reduce = f=> Y(h=> start=> arr=>
arr.length === 0
? start
: h (f (start) (arr[0])) (arr.slice(1)));
// filter
const filter = f=>
reduce(result=> x=>
f(x) ? result.concat([x]) : result) ([]);
// your examples again...
var myArray = [1,2,3,4,5];
filter (x=> x % 5 === 0) (myArray) //=> [5]
filter (x=> x <= 5) (myArray) //=> [1, 2, 3, 4, 5]
Why am i not hitting the last element of the array?
I don't know. It might be an error in your each-function, wich is not posted here. But since you have some more flaws in boh of your functions, I'll add a working implementation.
I've noticed that prev and curr actually never return 5 at any point of the reduce function.
prev and curr never return anything, they are arguments. And that particular function itself, also doesn't ever return anything.
First start === undefined is no proper check to determine wether yo want to initialize the result-value with the first(current)-element. undefined is an unexpected, even unwanted value in that place, but it is actually perfectly fine. So with that check, your reduce-function might start over again, in the middle of the collection.
Just take a look at the previously mentioned function you utilize in filter. This function does return undefined (as the value for the next iteration) ;) so that prev will always be undefined in your code.
Then, reduce makes no sense in your filter-function, at least the way you use it. You use it as each.
function reduce(collection, combine, start){
var result = start, hasValue = arguments.length > 2;
each(collection, function(element){
if(hasValue){
result = combine(result, element);
}else{
result = element;
hasValue = true;
}
});
if(!hasValue){
//no start/default-value, no elements in the collection,
//what result do you expect from this reduce-task?
throw new Error("reduce of empty array with no initial value");
}
return result;
}
function filter(collection, predicate){
return reduce(collection, function(result, elm){
//the functional-approach: no mutations
return predicate(elm)?
result.concat( [elm] ):
result;
//or a more sane way to do this in JS
if( predicate(elm) ) result.push( elm );
return result;
}, []);
}
Essentially I want to port the solution for: Python spliting a list based on a delimiter word to JavaScript.
Given: var example = ['A', 'WORD', 'B' , 'C' , 'WORD' , 'D'];
If a delimiter of WORD is provided I would like to generate:
var result = [['A'], ['WORD','B','C'],['WORD','D']];
Is there an alternative to looping through the list to do this?
The best approach here is to first write down the algorithm, without getting into specific code. Sometimes this is called pseudo-code. Have you tried writing some? Here's an example:
Start off with an empty result of the form [[]]. The inner array we will call subarray.
Look at the next word in the input. If it's 'WORD', then add a new subarray to the result and make it the current subarray.
Add the word to the current subarray.
Repeat until input is empty.
This type of algorithm, where we are looping over an array, and building up some kind of result, is exactly what reduce was designed for. We can transform the pseudo-code above almost directly into JS as follows:
function split(array) {
var subarray = []; // subarray we are adding elts to
return array.reduce( // loop over the array
function(result, elt) { // and for each element
if (elt === 'WORD') // if it is word, then...
result.push(subarray = []); // start a new subarray and add to result
subarray.push(elt); // add the current element to the subarray
return result; // and return the updated result
},
[subarray]); // start off with an array with a single subarray
}
Using generators
If you are working in an ES6 environment, you could use ES6 generators:
function* group(array) {
var subarray = [];
for (var elt of array) {
if (elt === 'WORD') {
yield subarray;
subarray = [];
}
subarray.push(elt);
}
yield subarray;
}
Here, array can actually be any iterable, since we are using for..of to get its values.
Now you can print out your subarrays by
for (grp of group(example)) console.log(grp);
Or create an array of the groups:
Array.from(group(examples))
Is there an alternative to looping through the list to do this?
Someone is going to have to loop, be it you or some library routine. In the first case, it is reduce doing the looping; in the ES6 code, it is the generator.
this should do what you ask
var tree = function (seq, breaks) {
var res = [], n;
for(var i = 0; i < seq.length; ) {
if(breaks.indexOf(seq[i]) != -1) {
for(var j = i+1; j < seq.length; j++) {
if(breaks.indexOf(seq[j]) != -1) {
break;
}
}
n = j;
var branch = tree(seq.slice(i+1, n), breaks);
branch.unshift(seq[i]);
res.push(branch);
i+=branch.length;
} else {
res.push([seq[i]]);
i++;
}
}
return res;
}
use
tree(['A', 'WORD', 'B' , 'C' , 'WORD' , 'D'], ['WORD'])
I would like to scan through a JS array and determine if all the elements are unique, or whether the array contains duplicates.
example :
my_array1 = [1, 2, 3]
my_array2 = [1, 1, 1]
I want get result like this :
my_array1 must be return true, because this array element is unique
and array2 must be return false, because this array element is not unique
How can I go about writing this method?
Sort your array first of all, and then go for a simple comparison loop.
function checkIfArrayIsUnique(arr) {
var myArray = arr.sort();
for (var i = 0; i < myArray.length; i++) {
if (myArray.indexOf(myArray[i]) !== myArray.lastIndexOf(myArray[i])) {
return false;
}
}
return true;
}
if you want to check for uniqueness you can also do this.As stated on the comment i do not assert this is as the only best option.There are some great answers down below.
var arr = [2,3,4,6,7,8,9];
var uniq = []; // we will use this to store the unique numbers found
// in the process for doing the comparison
var result = arr.slice(0).every(function(item, index, array){
if(uniq.indexOf(item) > -1){
// short circuit the loop
array.length=0; //(B)
return false;
}else{
uniq.push(item);
return true;
}
});
result --> true
arr.slice(0) creates a temporary copy of the array, on which the actual processing is done.This is because when the uniqueness criteria is met i clear the array (B) to short circuit the loop.This will make sure the processing stops as soon as the criteria is met.
And will be more nicer if we expose this as a method on a Array instance.
so we can do something like this [1,2,3,5,7].isUnique();
Add the following snippet and you are ready to go
Array.prototype.isUnique = function() {
var uniq = [];
var result = this.slice(0).every(function(item, index, arr) {
if (uniq.indexOf(item) > -1) {
arr.length = 0;
return false;
} else {
uniq.push(item);
return true;
}
});
return result;
};
arr.isUnique() --> true
DEMO
You may try like this:
function uniqueArray(arr) {
var hash = {}, result = [];
for ( var i = 0, l = arr.length; i < l; ++i ) {
if ( !hash.hasOwnProperty(arr[i]) ) {
hash[ arr[i] ] = true;
result.push(arr[i]);
}
}
return result;
}
try this :-
var my_array1 = [1, 2, 3]
var my_array2 = [1, 1, 1]
function isUnique(obj)
{
var unique=obj.filter(function(itm,i,a){
return i==a.indexOf(itm);
});
return unique.length == obj.length;
}
alert(isUnique(my_array1))
alert(isUnique(my_array2))
Demo
I think you can try with Underscore js , a powerful javascript library
Example the way to use underscore
function checkUniqueArr(arr){
var unique_arr = _.uniq(arr);
return arr.length == unique_arr.length;
}
The most efficient way to test uniqueness is:
function isUnique(arr) {
for(var i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) != i) return false;
}
return true;
}
This is O(n2) at worst case. At most time, it doesn't need to finish scanning for not-unique array.
function containsDuplicates(arr) {
var seen = {};
var duplicate = false;
for (var i = 0; i < arr.length; i++) {
if (seen[arr[i]]) {
duplicate = true;
break;
}
seen[arr[i]] = true;
}
return duplicate;
}
jsFiddle
Best-case: O(1) time and space - second element is the duplicate
Average/worst-case: O(n) time and space - no duplicates, or the duplicate is in the middle
Many of the answers here seem to be relying on some complex interspersion of array methods, which are inherently iterative, and generally don't seem appropriate for this fairly simple task. Algorithmically, this problem can be solved in O(n) time, but any nesting of indexOf/filter/map (or similar array methods) in a for loop means that your computation time will grow (at best) quadratically with your array size, rather than linearly. This is inefficient in time.
Now, in general, micro-optimization really is not necessary unless you have identified this to be a performance bottleneck in your application. But this kind of algorithm, in my opinion, is something you design (in pseudocode) and match to your application's needs before you even start coding. If you will have a huge data-set in your array, you will probably appreciate not having to look through it several times to get your answer. Of course, the caveat here is that you're trading time complexity for space complexity, since my solution requires O(n) space for caching previously seen values.
If you need to check all element are unique then following will do the trick
<script>
my_array1 = [11, 20, 3]
my_array2 = [11, 11, 11]
var sorted1= my_array1.sort();
var sorted2= my_array2.sort();
if(sorted1[0]==sorted1[sorted1.length-1])
alert('all same');
if(sorted2[0]==sorted2[sorted2.length-1])
alert('all same');
</script>
I just came up with this answer.
I'm preparing for an interview.
I think this is rock solid.
let r = [1,9,2,3,8];
let r2 = [9,3,6,3,8];
let isThereDuplicates= r.slice().sort().some((item,index,ar)=>(item ===ar[index+1]));
console.log('r is: ',isThereDuplicates) // -> false. All numbers are unique
isThereDuplicates= r2.slice().sort().some((item,index,ar)=>(item ===ar[index+1]));
console.log('r2 is: ',isThereDuplicates) //->true. 3 is duplicated
I first slice and sort without mutating the original array.
r.slice().sort()
Then I check that for at least one item, item is equal to the next item on the array.
.some((item,index,array)=>
item === array[index+1]
);
I have an array of objects in javascript. I use jquery.
How do i get the first element in the array? I cant use the array index - as I assign each elements index when I am adding the objects to the array. So the indexes arent 0, 1, 2 etc.
Just need to get the first element of the array?
If you don't use sequentially numbered elements, you'll have to loop through until you hit the first one:
var firstIndex = 0;
while (firstIndex < myarray.length && myarray[firstIndex] === undefined) {
firstIndex++;
}
if (firstIndex < myarray.length) {
var firstElement = myarray[firstIndex];
} else {
// no elements.
}
or some equivalently silly construction. This gets you the first item's index, which you might or might not care about it.
If this is something you need to do often, you should keep a lookaside reference to the current first valid index, so this becomes an O(1) operation instead of O(n) every time. If you're frequently needing to iterate through a truly sparse array, consider another data structure, like keeping an object alongside it that back-maps ordinal results to indexes, or something that fits your data.
The filter method works with sparse arrays.
var first = array.filter(x => true)[0];
Have you considered:
function getFirstIndex(array){
var result;
if(array instanceof Array){
for(var i in array){
result = i;
break;
}
} else {
return null;
}
return result;
}
?
And as a way to get the last element in the array:
function getLastIndex(array){
var result;
if(array instanceof Array){
result = array.push("");
array.pop;
}
} else {
return null;
}
return result;
}
Neither of these uses jquery.
Object.keys(array)[0] returns the index (in String form) of the first element in the sparse array.
var array = [];
array[2] = true;
array[5] = undefined;
var keys = Object.keys(array); // => ["2", "5"]
var first = Number(keys[0]); // => 2
var last = Number(keys[keys.length - 1]); // => 5
I was also facing a similar problem and was surprised that no one has considered the following:
var testArray = [];
testArray [1245]= 31;
testArray[2045] = 45;
for(index in testArray){
console.log(index+','+testArray[index])
}
The above will produce
1245,31
2045,45
If needed you could exist after the first iteration if all that was required but generally we need to know where in the array to begin.
This is a proposal with ES5 method with Array#some.
The code gets the first nonsparse element and the index. The iteration stops immediately with returning true in the callback:
var a = [, , 22, 33],
value,
index;
a.some(function (v, i) {
value = v;
index = i;
return true;
});
console.log(index, value);
If you find yourself needing to do manipulation of arrays a lot, you might be interested in the Underscore library. It provides utility methods for manipulating arrays, for example compact:
var yourArray = [];
yourArray[10] = "foo";
var firstValue = _.compact(yourArray)[0];
However, it does sound like you are doing something strange when you are constructing your array. Perhaps Array.push would help you out?