What is a fast way to find combinations that aren't present in an array yet?
E.g, I have list of points: [1, 2, 4, 9]
And I have a list of connections [[1,2], [1,4], [1,9], [2,4], [4,9]]
So the missing connection in this list is [2,9]. As there is one requirement: every integer must be connected to a bigger integer.
var points = [1, 2, 4, 9];
var connections = [[1,2], [1,4], [1,9], [2,4], [4,9]];
var missing = [];
for(i = 0; i < points.length; i++){
for(j = i + 1; j < points.length; j++){
var found = false;
for(var a = 0; a < connections.length; a++){
if(connections[a][0] == points[i] && connections[a][1] == points[j]){
found = true;
break;
}
}
if(!found) missing.push([points[i], points[j]]);
}
}
console.log(missing);
The above code works, but the amount of for loops makes me think it is reasonably slow. Is there any faster way to do this? View jsfiddle
By sorting the array, you can do it with 2 nests. Sorting takes O(n log n), and the loops are basically O(n ^ 2).
var points = [1, 2, 4, 9];
var connections = [
[1, 2],
[1, 4],
[1, 9],
[2, 4],
[4, 9]
];
connections.sort();
var missing = [];
var currentIndex = 0;
for (var i = 0; i < points.length; i++) {
for (var j = i + 1; j < points.length; j++) {
if (connections[currentIndex][0] == points[i] && connections[currentIndex][1] == points[j]) {
currentIndex++;
} else {
missing.push([points[i], points[j]]);
}
}
}
console.log(missing);
You can use .reduce method in order to generate all the combination of two elements.Then the only thing that will remain is to get the difference from two arrays.
For this, you can use filter method which accepts a callback method.
var points = [1, 2, 4, 9];
points=points.sort();
var connections = [[1,2], [1,4], [1,9], [2,4], [4,9]];
var combinations = points.reduce(function(arr,elem,i){
for(j=i+1;j<points.length;j++)
arr.push([elem,points[j]]);
return arr;
},[]);
var diff=combinations.filter(function(elem,i){
return connections.find(a=>a[0]==elem[0] && a[1]==elem[1])==undefined;
});
console.log(diff);
You could iterate only the outer loop until length - 2 and use a hash table for inserted connections. The sort order of connections does not matter.
var points = [1, 2, 4, 9],
connections = [[1, 2], [1, 4], [1, 9], [2, 4], [4, 9]],
missing = [],
i, j,
pair,
connected = Object.create(null);
connections.forEach(function (a) {
connected[a.join()] = true;
});
for (i = 0; i < points.length - 1; i++) {
for (j = i + 1; j < points.length; j++) {
pair = [points[i], points[j]];
connected[pair.join()] || missing.push(pair);
}
}
console.log(missing);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I am trying to write a function that will take an array and n as parameters,
it will return all subsets of that array with n elements, have tried a couple things, couldn't yet succeed.
thanks to whoever put it here, this functions is way too complicated and doesn't do the job, basically what I tried to do here is to pick out one element from a 4 element array to create its 3 element subsets. It doesn't even take N as parameter. it returns all 3 element subsets but also identical ones, so I have to filter them out as well, in any case I will keep trying.
function findSubsets(array) {
var answers = [];
var firstArray = array;
for (i = 0; i < array.length; i++) {
array = firstArray;
for (var k = 0; k < array.length; k++) {
if (k != i) {
var subset = array.splice(k, 1);
answers.push(array); array.splice(k, 0, subset[0]);
}
}
}
}
That not as complicated as it seems. This one is optimized because it doesn't creates useless temporary arrays during the process.
function findSubsets(array, n) {
var answers = [];
for(var i = 0 ; i < array.length ; i += n) {
answers.push(array.slice(i, i + n));
}
return answers;
}
findSubsets([1, 2, 3, 4, 5, 6, 7, 8, 9], 2) // --> [[1, 2], [3, 4], [5, 6], [7, 8], [9]]
findSubsets([1, 2, 3, 4, 5, 6, 7, 8, 9], 3) // --> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
You can try this solution
var subsetArray = (function() {
return {
getResult: getResult
}
function getResult(array, n) {
function isBigEnough(value) {
return value.length === n;
}
var ps = [
[]
];
for (var i = 0; i < array.length; i++) {
for (var j = 0, len = ps.length; j < len; j++) {
ps.push(ps[j].concat(array[i]));
}
}
return ps.filter(isBigEnough);
}
})();
var arr = [1, 2, 3, 4,5,6,7,8,9];
console.log(subsetArray.getResult(arr,2));
Below is the code :
function chunkArrayInGroups(arr, size) {
// Break it up.
var newArr =[];
for(var i = 0;i < arr.length;i++){
for(var j = 0;j < size;j++){
newArr.push(arr.splice(0,size));
}
}
var result = [];
for(i = 0;i < newArr.length;i++){
if(newArr[i].length != 0){
result.push(newArr[i]);
}
}
return result;
}
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7,8], 2);
This should return - [[0, 1], [2, 3], [4, 5], [6, 7], [8]]. However, the code returns [[0, 1], [2, 3], [4, 5], [6, 7]]. Also, if my input array is ([0,1,2,3,4,5,6,7,8,9,10],2) my code returns as expected.
P.S: I am specifically looking to find what's wrong with this code instead of a different code/approach altogether.
Basically you need just one loop, because you splice the array and take a chunk of the wanted size of it.
This behaviour could be used to loop until the array has a length of zero and exit the loop.
In this case the result is ready.
function chunkArrayInGroups(arr, size) {
var newArr = [];
// for (var i = 0; i < arr.length; i++) {
while (arr.length) { // add this for looping and checking
// for (var j = 0; j < size; j++) {
newArr.push(arr.splice(0, size)); // keep this for doing the work!
// }
}
// var result = [];
// for (i = 0; i < newArr.length; i++) {
// if (newArr[i].length != 0) {
// result.push(newArr[i]);
// }
// }
// return result;
return newArr; // return only newArray
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can just do the following:
var size = 2;
var arr = [0,1,2,3,4,5,6,7,8];
var newArray = [];
for(var i = 0; i < arr.length; i+=size){
newArray.push(arr.slice(i,i+size))
}
console.log(newArray); //will output [[0,1],[2,3],[4,5],[6,7],[8]]
Your problem is that you are not treating the case where the remaining in the array is less than the given size, in other words the case when arr.length < size, so the remaining items in the array won't be taken into account in the chunk array.
You need to test upon it, I updated your code so it works perfectly:
function chunkArrayInGroups(arr, size) {
// Break it up.
var newArr =[];
while(size<arr.length){
newArr.push(arr.splice(0, size ));
}
if(arr.length<size){
newArr.push(arr);
}
}
Demo:
function chunkArrayInGroups(arr, size) {
// Break it up.
var newArr =[];
while(size<arr.length){
newArr.push(arr.splice(0, size));
}
if(arr.length<size){
newArr.push(arr);
}
return newArr;
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7,8], 2));
Note:
There's no need for using the result array as it's just a copy of the newArr, you could just return newArr without copying it.
I want to collect all subarrays for further computation efficiently in javascript. I'm not sure this is possible, but it seems for a subarray sum kadane's formula is o(n) which is more efficient than other methods. But I'm not sure I how I can store the array at each step.
Similar to this quora question, for me the pseudo code was not enough. Thanks for the further breakdown.
another meta link
an example in action of this for [3, 3, 9, 9, 5]
[3], [9], [5], [9, 5], [9, 3], [9, 9], [3, 3],
[3, 9, 9], [3, 3, 9], [9, 9, 5], [3, 3, 9, 9],
[3, 9, 9, 5], [3, 3, 9, 9, 5]
I had done a work previously to calculate all combinations of amino acids total molecular weight. If you neglect the empty one you should have 2^n - 1 sub arrays. So there is no O(n) here. I've got two methods as binary and recursive.
function getSubArrays(arr){
var len = arr.length,
subs = Array(Math.pow(2,len)).fill();
return subs.map((_,i) => { var j = -1,
k = i,
res = [];
while (++j < len ) {
k & 1 && res.push(arr[j]);
k = k >> 1;
}
return res;
}).slice(1);
}
console.log(JSON.stringify(getSubArrays([1,2,3,4,5])));
function getSubArrays(arr){
if (arr.length === 1) return [arr];
else {
subarr = getSubArrays(arr.slice(1));
return subarr.concat(subarr.map(e => e.concat(arr[0])), [[arr[0]]]);
}
}
console.log(JSON.stringify(getSubArrays([1,2,3,4,5])));
I couldn't manage to get subarrays of an array with more than 23 items though.
Here are the performances. To be on the safe side i try with 22 items, first with recursive and then with binary route.
function getSubArrays(arr){
if (arr.length === 1) return [arr];
else {
subarr = getSubArrays(arr.slice(1));
return subarr.concat(subarr.map(e => e.concat(arr[0])), [[arr[0]]]);
}
}
var aminos = Array(22).fill().map((_,i) => i+1),
subarrs = [],
ps = 0,
pe = 0;
ps = performance.now();
subarrs = getSubArrays(aminos);
pe = performance.now();
console.log("recursive route took: " + (pe-ps) + "msec to produce " + subarrs.length + " sub arrays");
function getSubArrays(arr){
var len = arr.length,
subs = Array(Math.pow(2,len)).fill();
return subs.map((_,i) => { var j = -1,
k = i,
res = [];
while (++j < len ) {
k & 1 && res.push(arr[j]);
k = k >> 1;
}
return res;
}).slice(1);
}
var aminos = Array(22).fill().map((_,i) => i+1),
subarrs = [],
ps = 0,
pe = 0;
ps = performance.now();
subarrs = getSubArrays(aminos);
pe = performance.now();
console.log("binary route took: " + (pe-ps) + "msec to produce " + subarrs.length + " sub arrays");
This is fairly simple to do: https://jsfiddle.net/j1LuvxLq/
All you do is iterate possible lenghts and starting points and just print out the subsets. Complexity is O(n²) where n is the length of the original array. No way to improve it thought because that's the order of how many subsets there are.
var set = [3, 3, 9, 9, 5].join('')
var set_length = set.length
var subsets = []
for (var length_of_subset = 1; length_of_subset <= set_length; length_of_subset++) {
for (var start_of_subset = 0; start_of_subset <= set_length - length_of_subset; start_of_subset++) {
var current_subset = set.substring(start_of_subset, start_of_subset + length_of_subset)
if(subsets.indexOf(current_subset) == -1) {
subsets.push(current_subset.split(''))
}
}
}
// print the subsets out
for (s in subsets) {
$('body').append(subsets[s].join(', ') + '<br>')
}
Alternative, possibly nicer solution would be to use dynamic programming. Start with 3 and either remove last element or add next element. Check it out here: https://jsfiddle.net/p82fcs4m/
var set = [3, 3, 9, 9, 5].join('')
var subsets = []
take(set[0], set.substring(1))
function take(chosen, left) {
if(subsets.indexOf(chosen) != -1) {
return
}
subsets.push(chosen)
if (chosen.length > 1) {
take(chosen.substring(1), left)
}
if (left.length > 0) {
take(chosen.concat(left[0]), left.substring(1))
}
}
$('body').append(subsets.join('<br>'))
Try this:
function getSubArrays(arr) {
const subArrays = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i; j++) {
const subArray = arr.slice(i, j + i + 1);
subArrays.push(subArray);
}
}
}
Still O(n²) tho
I believe using Array.slice is the most clean way to do it, isn't it?
function getSubArrays(arr) {
const subArrays = [];
for (var i = 0; i < arr.length; i++) {
for (var j = i; j < arr.length; j++) {
subArrays.push(arr.slice(i, j + 1));
}
}
return subArrays;
}
I'm building an app to test different icons. Admins upload a number of icons and input how many icons must be shown at the same time. The app then displays all possible sets of icons in sequence until all combination of icons have been shown.
Now, I need a function to generate all unique icons combinations based on two number:
the number of total icons (i)
the number of icons in each set (s)
If i = 6 and s = 3, I want the output to look as follows:
[
[1, 2, 3],
[1, 2, 4],
[1, 2, 5],
[1, 2, 6],
[1, 3, 4],
[1, 3, 5],
[1, 3, 6],
[1, 4, 5],
[1, 4, 6],
[1, 5, 6],
[2, 3, 4],
[2, 3, 5],
[2, 3, 6],
[2, 4, 5],
[2, 4, 6],
[2, 5, 6],
[3, 4, 5],
[3, 4, 6],
[3, 5, 6],
[4, 5, 6],
]
Requirements:
All sets have to be unique
A number can only occur one time in a set
I have been trying to code a recursive function, but I havent anything really anything to show. I can't get my head around it :(
Based off the idea given as an answer to this question:
Computing all n-sized permutations without repetitions and without "classic" ordering
Then use C++ std::next_permutation like algorithms which work as
follows:
Go from left and find rightmost one preceeded by zero. Put one in
place of zero and sort the rest of array.
Disclaimer: My javascript is very, very rusty so I'm sure there is a much more elegant way of implementing this.
function combine(n, k) {
var result = [];
// initialize array of values
var values = [];
for (var i = 1; i <= n; i++) {
values[i - 1] = i;
}
// initialize permutations
var perm = [];
for (var i = 0; i < n; i++) {
if (i < k) {
perm[i] = 1;
} else {
perm[i] = 0;
}
}
perm.sort();
whileloop:
while (true) {
// save subresult
var subresult = [];
for (var i = 0; i < n; i++) {
if (perm[i] == 1) {
subresult.push(values[i]);
}
}
result.push(subresult);
// get next permutation
for (var i = n - 1; i > 0; i--) {
if (perm[i - 1] == 1) {
continue;
}
if (perm[i] == 1) {
perm[i - 1] = 1;
perm[i] = 0;
perm = perm.slice(0, i).concat(perm.slice(i).sort())
continue whileloop;
}
}
// no additional permutations exist
break whileloop;
}
return result;
}
Combining n elements in to number of sets with k elements each without repetitions, how to do it.
The algorithm is relatively simple, main idea: we consequently feed first set of k elements and then try to increment each element from the end of set to populate another k-set and so on.
When we can't do that we leave the process (all possible sets are ready).
function combine(n,k) {
var result = Array();
var a = Array();
// make initial (first) k-set
for (var i=1; i<=k; i++) {
a[i-1] = i;
}
j = k-1;
while (j >= 1) {
// submit current results
result.push(a.slice());
if (a[k-1] == n) {
j = j - 1;
} else {
j = k-1;
}
if (j >= 1) {
// make next k-set based on previous one
for (var i=k; i>=j; i--) {
a[i-1] = a[j-1] + i - j + 1;
}
}
}
return result;
}
Note: JavaScript arrays have start index 0 so in code we have -1 correction for array indices (cause set of possible values from 1 to n)
I'm trying to animate the sorting of a few elements with jQuery and my sorting map is defined like this:
var mapping = [
[0, 5],
[1, 4],
[2, 3],
[3, 2],
[4, 1],
[5, 0]
];
mapping[0][0] is the element's index and mapping[0][1] is the target index.
My solution was basically this:
var elements = [1, 2, 3, 4, 5, 6];
for (var i = 0; i < elements.length; i++) {
var clone1 = elements[mapping[i][0]];
var clone2 = elements[mapping[i][1]];
elements[mapping[i][0]] = clone2;
elements[mapping[i][1]] = clone1;
}
console.log(elements);
The problem is, I am working on the object I'm modifying and the operations undo themselves; instead of reversing the array, I get the same array back.
How would I swap elements like this in JavaScript? Here's a JSFiddle example of the code.
// [source, target]
var mapping = [
[0, 5],
[1, 4],
[2, 3],
[3, 2],
[4, 1],
[5, 0]
];
var elements = [1, 2, 3, 4, 5, 6];
function swapElements(elements, mapping) {
var tmp = new Array(elements.length);
for(var i = 0, l = mapping.length; i < l; i++) {
tmp[mapping[i][1]] = elements[mapping[i][0]];
}
for(var i = 0, l = elements.length; i < l; i++) {
elements[i] = tmp[i];
}
}
swapElements(elements, mapping);
console.log(elements);
Some functional fun with accessor function
var at = function(arr) { return function(i) { return arr[i] } };
[5,4,3,2,0,1].map( at(['a','b','c','d','e','f']) )
this will returns ['f','e','d','c','a','b']
You swap elements twice from 0 to 5 and from 5 to 0 again :) Try
for (var i = 0; i < elements.length / 2; i++)
and it will be ok.
Look here
You're changing the array during a loop of it. And it's swapped twice for each pair, so the result is the same. You may need another arr to store mapped value:
var result = [];
for(var i = 0; i<mapping.length; i++){
result[mapping[i][0]] = elements[mapping[i][1]];
}
console.log(result);
Just define a temporary array:
var elements = [1, 2, 3, 4, 5, 6];
var temp = [];
for (var i = 0; i < elements.length; i++) {
temp.push(elements[mapping[i][1]]);
}
elements = temp;
Just_Mad's answer is correct if you are only trying to reverse the list. But if you want to be able to handle any mapping configuration you will need a different approach.
If you don't care about memory space you could just iterate through the mapping list and copy the element at index "mapping[i][0]" to a new array at index "mapping [i][1]". Then just return the new array. This should handle whatever mapping you put into the system (you just have to decide if and how you want to handle mappings that leave empty spaces and/or override spaces)