I want to reorder an array of distinct elements to look like a second array, but only using move operations.
Example:
Index 0 1 2 3 4
Array e b a c d
Order a b c d e
Moving operations (insert at target index):
original e b a c d
0→4 b a c d e
1→0 a b c d e
I would like to minimize the amount of moving operations and get a list of the operations (from/to index) as a result.
My background is that I fetch and sort a list of IDs from a server using javascript. However, I can only update the sorting by single-element "move to index" commands to their API.
Solution 1:
a) use the ordered array and insert all elements at the end
b) or at position 0 in reverse order.
That would require N operations for N elements, though, even for the best case.
Solution 2:
Iterate the ordered array and move elements into ordered position.
Furthermore, the element previously there is move to its desired position.
The latter helps if two letters are swapped, as in e b c d a.
While that reduces the best case scenario to 0 moves, most random cases require >N operations for N elements.
Code example for Solution 2:
function arraymove(arr, fromIndex, toIndex) {
var element = arr[fromIndex];
arr.splice(fromIndex, 1);
arr.splice(toIndex, 0, element);
}
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
let newOrder = [...Array(20).keys()];
let oldOrder = [...newOrder];
//oldOrder.reverse() //reverse case
shuffleArray(oldOrder); //random case
//arraymove(oldOrder, 0, 99); //end to beginning case
let checkOrder = [...oldOrder];
let moveOrder = [];
for (ind = newOrder.length - 1; ind >= 0; --ind) {
let el = newOrder[ind];
if (checkOrder[ind] != el) {
let oldind = checkOrder.indexOf(el);
let altel = checkOrder[ind];
arraymove(checkOrder, oldind, ind);
moveOrder.push({ el: el, ind: ind, old: oldind });
let altind = checkOrder.indexOf(altel);
if (newOrder[newOrder] != altel) {
let newind = newOrder.indexOf(altel);
arraymove(checkOrder, altind, newind);
moveOrder.push({ el: altel, ind: newind, old: altind });
}
}
}
document.write("oldOrder: ", oldOrder.join(" "),"<br> Moves: ", moveOrder.length);
Is there a better solution, or perhaps an already established algorithm I didn't find?
The example from above is sadly not found by Solution 2.
Related
Maybe I have misunderstanding on Merge sort. Can someone explain to me if I break the toBeSorted list into array of sub arrays like this:
const toBeSorted = [2,4,5,1,6,8]
const brokenDown = [[2],[4],[5],[1],[6],[8]]
then I do the usual sort and merge thing with the subarrays inside brokenDown. What is the difference or drawbacks comparing to the classic original solution?
I understand merge sort as halving the original list down till each sub array only contain one item, then sort them and merge them together. So instead of halving, I just iterate through the original array and make it an array of subarrays.
I tried both solutions, the classic one took around 3000ms to sort 200,000 while my solution took 5000ms to sort the same amount of data.
So I think I am lacking some understanding on Merge Sort.
my solution full code:
(() => {
let i = 0
const data = []
const size = 200000
while (i < size) {
data.push(Math.round(Math.random() * 1000))
i++
}
function mergeSort(arr) {
if (arr.length < 2) return arr[0]
const output = []
for (let i=0; i<arr.length; i+=2) {
output.push(sortAndStitch(arr[i], arr[i+1]))
}
return mergeSort(output)
}
function breakDown(arr) {
const output = []
for (item of data) {
output.push([item])
}
return output
}
function sortAndStitch(sub1, sub2) {
const arr1 = sub1 || [], arr2 = sub2 || [], output = []
while(arr1.length && arr2.length) {
if (arr1[0] > arr2[0]) {
output.push(arr2.shift())
} else {
output.push(arr1.shift())
}
}
return output.concat(...arr1, ...arr2)
}
const start = new Date().getTime()
mergeSort(breakDown(data))
const interval = new Date().getTime() - start + 'ms'
console.log({ size, interval })
})()
the classic solution that I am comparing to:
(() => {
let i = 0
const data = []
const size = 200000
while (i < size) {
data.push(Math.round(Math.random() * 1000))
i++
}
const mergeSort = nums => {
if (nums.length < 2) {
return nums;
}
const length = nums.length;
const middle = Math.floor(length / 2);
const left = nums.slice(0, middle);
const right = nums.slice(middle);
return merge(mergeSort(left), mergeSort(right));
};
const merge = (left, right) => {
const results = [];
while (left.length && right.length) {
if (left[0] <= right[0]) {
results.push(left.shift());
}
else {
results.push(right.shift());
}
}
return results.concat(left, right);
};
const start = new Date().getTime()
mergeSort(data)
const interval = new Date().getTime() - start + 'ms'
console.log({ size, interval })
})()
The first example pushes n = 200,000 sub-arrays of size 1 to create an array of n = 200,000 sub-arrays. Then for each "pass", it indexes two sub-arrays from the array of sub-arrays, merges them into a single sub-array, and pushes that sub-array onto yet another array of sub-arrays. So the code ends up creating 19 arrays of sub-arrays (including the original), by pushing the sub-arrays onto arrays of sub-arrays, which ends up as 400000+ pushes of sub-arrays onto arrays of sub-arrays. Those arrays of sub-arrays are also consuming a lot of space.
The second example splits the array into two sub-arrays, then recursion follows only the left sub-arrays until a sub-array of size 1 is reached, then a right sub-array of size 1 is reached, and only then does merging begin, following the call chain up and down, depth first, left first. Only 18 levels of recursion occur, and the shifts and pushes are only performed on arrays of numbers, while the first example is also performing those 400000+ pushes of sub-arrays onto arrays of sub-arrays.
An indexed based merge sort (top down or bottom up) would be much faster for either first or second example, taking about 50 ms to sort 200,000 numbers. As commented above, Wikipedia has psuedo code examples:
https://en.wikipedia.org/wiki/Merge_sort
classic original solution
The "classic original solution" is bottom up merge sort. The 1945 EDVAC that Von Newmann described a merge sort for didn't have a stack. Prior to that, Hollerith card sorters, dating back to 1887, used radix sort. The IBM type 77 collators (1937) could merge two decks of sorted cards into a single merged deck, which is what probably gave Von Newmann the idea of merge sort in 1945, followed up in 1948 with a description and analysis of bottom up merge sort.
The first practical non-punched card based sorts were tape sorts (variations of bottom up merge sort), used on the Univac 1 (early 1950's) which could have up to 10 Uniservo tape drives.
Most libraries use some variation of hybrid insertion (on small sub-arrays) + bottom up merge sort for stable sort. Run time for insertion + top down merge sort is about the same, but recursion could throw a stack overflow exception mid-sort. Example hybrid insertion + bottom up merge sort (on my system (Intel 3770K 3.5 ghz, Windows 7 Pro 64 bit, to sort 200,000 numbers, Chrome takes ~40 ms, IE 11 takes ~35 ms.
function merge(a, b, bgn, mid, end) {
var i = bgn // left: a[bgn,mid)
var j = mid // right: a[mid,end)
var k = bgn // index for b[]
while(true){
if(a[i] <= a[j]){ // if left <= right
b[k++] = a[i++] // copy left
if(i < mid) // if not end of left
continue // continue back to while
do // else copy rest of right
b[k++] = a[j++]
while(j < end)
break // and break
} else { // else left > right
b[k++] = a[j++] // copy right
if(j < end) // if not end of right
continue // continue back to while
do // else copy rest of left
b[k++] = a[i++]
while(i < mid)
break // and break
}
}
}
function insertionsort(a, ll, rr)
{
var i = ll+1
while(i < rr){
var t = a[i]
var j = i
while((j > ll) && a[j-1] > t){
a[j] = a[j-1]
j -= 1}
a[j] = t
i += 1}
}
function getpasscount(n) // return # passes
{
var i = 0
for(var s = 1; s < n; s <<= 1)
i += 1
return(i)
}
function mergesort(a)
{
var n = a.length
if(n < 2) // if size < 2 return
return
var b = new Array(n) // allocate temp array
var s = 64 // set run size
if(0 != (1&getpasscount(n))) // for even # of passes
s = 32
for(var rr = 0; rr < n; ){ // do insertion sorts
var ll = rr;
rr += s;
if(rr > n)
rr = n;
insertionsort(a, ll, rr);
}
while(s < n){ // while not done
var ee = 0 // reset end index
while(ee < n){ // merge pairs of runs
var ll = ee // ll = start of left run
var rr = ll+s // rr = start of right run
if(rr >= n){ // if only left run
do // copy it
b[ll] = a[ll]
while(++ll < n)
break // end of pass
}
ee = rr+s // ee = end of right run
if(ee > n)
ee = n
merge(a, b, ll, rr, ee) // merge a[left],a[right] to b[]
}
var t = a // swap array references
a = b
b = t
s <<= 1 // double the run size
}
}
var a = new Array(200000)
for (var i = 0; i < a.length; i++) {
a[i] = Math.round(Math.random() * 1000000000)
}
console.time('measure')
mergesort(a)
console.timeEnd('measure')
for (var i = 1; i < a.length; i++) {
if(a[i-1] > a[i]){
console.log('error')
break
}
}
I'm trying to speed-up matrices multiplications in pure javascript. Multiplications appear to be very slow above a few hundreds of lines, over the minute on a thousand of lines: you'll see the execution time bellow.
How would you solve this? We are working on a split + parallelization solution in Node.js so I'm looking for the best options to optimize it in pure javascript. My solution has to adapt the parallelized flows itself to the number of CPU threads available (that is unknown at design time).
Some data :
const math = require("mathjs");
// a1 is a 1000x1000 float matrix
// b1 is a 1000x400
math.multiply(a1, b1)
// runs in 19.6 seconds on a CPU 4.2Ghz
// a2 is 1600x1200
// b2 is 1200x800
math.multiply(a2, b2)
// runs in 78 seconds
Array lookup optimization
Arrays are associative lookup tables in JavaScipt - they are inefficient by nature. An optimization of this kind of array access
var array = some_2D_Array;
var nRows = array.length;
var nCols = array[0].length;
for( var r = 0; r < nRows; ++r) {
for( var c = 0; c < nCols; ++c) {
// do something with array[r][c];
}
}
is to replace it with
var array = some_2D_Array;
var nRows = array.length;
var nCols = array[0].length;
for( var r = 0; r < nRows; ++r) {
var aRow = array[r]; // lookup the row once
for( var c = 0; c < nCols; ++c) {
// do something with aRow[c];
}
}
which avoids searching the array object for the row array within each iteration of the inner loop. Performance gain will depend on the JS engine and the number of inner iterations.
Typed Array Usage
Another alternative could be to use a one dimensional typed array to avoid associative array index lookup instead of computing it. Here's some test code I ran in Node so see what difference it might make:
function Mat (rows, cols) {
var length = rows*cols,
buffer = new Float64Array( length)
;
function getRow( r) {
var start = r*cols,
inc = 1;
return { length: cols, start, inc, buffer};
}
function getCol( c) {
var start = c,
inc = cols;
return { length: rows, start, inc, buffer};
}
function setRC(r,c, to) {
buffer[ r*cols + c] = to;
}
this.rows = rows;
this.cols = cols;
this.buffer = buffer;
this.getRow = getRow;
this.getCol = getCol;
this.setRC = setRC;
}
Mat.dotProduct = function( vecA, vecB) {
var acc=0,
length = vecA.length,
a = vecA.start, aInc = vecA.inc, aBuf = vecA.buffer,
b = vecB.start, bInc = vecB.inc, bBuf = vecB.buffer
;
if( length != vecB.length) {
throw "dot product vectors of different length";
}
while( length--) {
acc += aBuf[ a] * bBuf[ b];
a += aInc;
b += bInc;
}
return acc;
}
Mat.mul = function( A, B, C) {
if( A.cols != B.rows) {
throw "A cols != B.rows";
}
if( !C) {
C = new Mat( A.rows, B.cols);
}
for( var r = 0; r < C.rows; ++r) {
var Arow = A.getRow(r);
for (var c = 0; c < C.cols; ++c) {
C.setRC( r, c, this.dotProduct( Arow, B.getCol(c)));
}
}
return C;
}
function test() {
// A.cols == B.rows
let side = 128;
let A = new Mat( side, side)
let B= new Mat( side, side);
A.buffer.fill(1)
B.buffer.fill(1)
console.log( "starting test");
let t0 = Date.now();
Mat.mul( A,B);
let t1 = Date.now();
console.log( "time: " + ((t1-t0)/1000).toFixed(2) +" seconds");
}
test()
Results for multiplying two square matrices (1.1Ghz Celeron):
// 128 x 128 = 0.05 seconds
// 256 x 256 = 0.14 seconds
// 512 x 512 = 7 seconds
// 768 x 768 = 25 seconds
// 1024 x 1024 = 58 seconds
The differences in CPU speed suggest this approach could be significantly faster but ... the code is experimental, the system had no other load and timings were for array multiplication alone - they exclude time taken to decode and populate the array with data. Any serious gain would need to be proven in practice.
I eventually decided that when multiplying two square matrices together, doubling the side dimension used should make the operation take 8 times as long: four times as many result elements to calculate and twice as many elements in vectors used to calculate dot products. The comparative times for 512 x 512 and 1024 x 1024 multiplications fit in line with this expectation.
I've seen versions of this question for other languages, but not for JS.
Is it possible to do this recursively in one function?
I understand that I need to take the first element in the string, and then append it to each solution to the recursion on the remainder of the string.
So logically, I understand how the recursion needs to go. I just don't understand how to append the first char onto each of the recursive solutions
var myString = "xyz";
function printPermut(inputString){
var outputString;
if(inputString.length === 0){
return inputString;
}
if(inputString.length === 1){
return inputString;
}
else{
for(int i = 0; i<inputString.length(); i++){
//something here like:
//outputString = outputString.concat(printPermut(inputString.slice(1))??
//maybe store each unique permutation to an array or something?
}
}
}
Let's write a function that returns all permutations of a string as an array. As you don't want any global variables, returning the permutations is crucial.
function permut(string) {
if (string.length < 2) return string; // This is our break condition
var permutations = []; // This array will hold our permutations
for (var i = 0; i < string.length; i++) {
var char = string[i];
// Cause we don't want any duplicates:
if (string.indexOf(char) != i) // if char was used already
continue; // skip it this time
var remainingString = string.slice(0, i) + string.slice(i + 1, string.length); //Note: you can concat Strings via '+' in JS
for (var subPermutation of permut(remainingString))
permutations.push(char + subPermutation)
}
return permutations;
}
To print them, just iterate over the array afterwards:
var myString = "xyz";
permutations = permut(myString);
for (permutation of permutations)
print(permutation) //Use the output method of your choice
Hope I could help you with your question.
The problem of permutations has been studied to death. Heap's algorithm is one well-known solution. Here is a version in JS, using a generator:
function *permute(a, n = a.length) {
if (n <= 1) yield a.slice();
else for (let i = 0; i < n; i++) {
yield *permute(a, n - 1);
const j = n % 2 ? 0 : i;
[a[n-1], a[j]] = [a[j], a[n-1]];
}
}
console.log(Array.from(permute("abcabad".split('')))
.map(perm => perm.join(''))
.filter((el, idx, self) => (self.indexOf(el) === idx)));
permute is designed to take and generate arrays, not strings, so we split the string into characters before calling it, and paste the characters back into strings before printing out the results.
Use Recursive Function to iterate through the string
function getPermutations(string) {
var results = [];
if (string.length === 1)
{
results.push(string);
return results;
}
for (var i = 0; i < string.length; i++)
{
var firstChar = string[i];
var otherChar = string.substring(0, i) + string.substring(i + 1);
var otherPermutations = getPermutations(otherChar);
for (var j = 0; j < otherPermutations.length; j++) {
results.push(firstChar + otherPermutations[j]);
}
}
return results;
}
var permutation = getPermutations('YES').filter((el, idx, self) => (self.indexOf(el) === idx));
console.log("Total permutation: "+permutation.length);
console.log(permutation);
Problem classification: You can look at this problem as an exploration problem, i.e., given a set of input characters explore the different ways you can arrange them.
Solution: Backtracking algorithm excels in solving exploratory problems, although it comes with high time complexity. To demonstrate a solution, imagine how you would solve this problem by hand for a small set of input characters: [a, b, c].
Here are the steps:
Take the left most character. This is the character at index 0 and swap it with target right character at index 0, i.e. with itself. This is because [a, b, c] is a valid permutation on its own therefore we want to keep it. Swapping characters normally requires two pointers which point to each of the characters. So let's say we will have a left and right pointer.
With the same left most character (at index 0) do the swapping with target right character at index 0 + 1 = 1, i.e. move the target right pointer with 1 step further. This will give you the output: [b, a, c]
With the same left most character (at index 0) do the swapping with the next next target right character (i.e. index 0 + 1 + 1 = 2). This will give you the output: [c, b, a]
Ok, now we need to stop as there are no more target right characters to be swapped with the left most character. So our right pointer needs to stay less than the max index in the input. Moving the right pointer with a step at a time we can do with a for loop which starts from the left index and ends with the input length - 1.
Now you need to do exact same steps from above but move the left pointer so that it points to the next left most character. However, keeping the input from step 2 and 3. Another way to imagine this situation is to say: 'Hey, I am done with the left most character. Now I do not want to work with it anymore but I would love to continue with the second left most from the results I have so far.'
When do we stop? When the left pointer has reached the length of the input string - 1, 'cause there is no more characters after this index. In recursive algorithms (such as the backtracking), the case where you need to stop is called base case. In our example the base case is: left === input.length - 1.
Here is a graphical visualisation:
left index| Input String:
-------------------------------------------------------------------------------
left = 0 | in=[a, b, c]
(swap in[0] with in[0]) (swap in[0] with in[1]) (swap in[0] with in[2])
left = 1 | in=[a, b, c] in=[b, a, c] in=[c, b, a]
(swap in[1] with in[1]) (swap in[1] with in[2]) (swap in[1] with in[1])(swap in[1] with in[2]) (swap in[1] with in[1])(swap in[1] with in[2])
left = 2 | [a, b, c] [a, c, b] [b, a, c] [b, c, a] [c, b, a] [c, a, b]
Summary:
To move the left pointer to the right we will use recursive increment
To move the right pointer to the right we will use a for loop, however we need to start always from the left pointer or else we will explore things we have already explored.
Backtracking:
A pseudo-code for backtracking algorithm takes the form of:
fun(input)
if(base_case_check(input)) {
//do final step
} else {
//choose
fun(reduce(input)) //explore
//un-choose
}
Our solution:
function permutate(string) {
if(!string || string.length === 0)
return new Set(['']);
let left = 0;
let result = new Set();
permutationHelper(string, result, left);
return result;
}
function permutationHelper(string, result, left) {
if(left === string.length-1) {
//base case
result.add(string);
} else {
//recursive case
for(let right=left; right < string.length; right++) {
string = swap(string, left, right); //choose
permutationHelper(string, result, left+1); // explore
string = swap(string, left, right); //unchoose
}
}
}
function swap(string, left, right) {
let tmpString = string.split('');
let tmp = tmpString[left];
tmpString[left] = tmpString[right];
tmpString[right] = tmp;
return tmpString.join('');
}
/* End of solution */
/* Tests */
let input = 'abc';
let result = permutate(input);
let expected = new Set(['abc', 'acb', 'bac', 'bca', 'cab', 'cba']);
if(setsEquality(result, expected)) {
console.log('Congrats, you generated all permuations');
} else {
console.log('Sorry, not all permuations are generated');
}
function setsEquality(actualResult, expectedResult) {
if (actualResult.size !== expectedResult.size) {
return false;
}
for (let permutation of actualResult) {
if (!expectedResult.has(permutation)) return false;
}
return true;
}
function assert(condition, desc) {
if (condition) {
console.log(`${desc} ... PASS`);
} else {
console.log(`${desc} ... FAIL`);
}
}
Summary & Time Complexity:
We make our choice by swapping characters in the existing input string
We explore what is left to be explored once we increment our left index with 1. This in fact means that we are reducing our input set for all subsequent recursions with 1. Therefore the work we need to do is: Nx(N-1)x(N-2)x(N-3)x...x1 = N!. However, as we needed a for loop to explore among the input we have, the total time complexity would be: 0(N*N!)
We revert our choice by swapping characters back in the modified input string
permutation=(str,prefix)=>{
if(str.length==0){
console.log(prefix);
}
else{
for(let i=0;i<str.length;i++){
let rem = str.substring(0,i)+str.substring(i+1);
permutation(rem,prefix+str[i]);
}
}
}
let str="ABC";
permutation(str,"");
Semi-Off topic:
random permutation of a given string is as simple as rndperm:
i = document.getElementById("word");
b = document.getElementById("butt");
rndperm = (z) => {
return z.split("").sort(() => ((Math.random() * 3) >> 0) - 1).join("")
}
function scramble() {
i.value = rndperm(i.value);
}
var z;
function sci() {
if (z != undefined) {
clearInterval(z);
b.innerText = "Scramble";
z=undefined;
} else {
z = setInterval(scramble, 100);
b.innerText = "Running...";
}
}
<center><input id="word" value="HelloWorld"></input><button id="butt" onclick=sci()>Scramble</button></center>
I had same question by my interviewer last day but I was not get the correct logic then I came to stackoverflow and I get here but now I have my solution and want to share with all
const str_Permutations = (str,ar = []) => {
str = `${str}`; // ensure type **String**
if(ar.indexOf(str)>-1 || str.length !== (ar.strlen || str.length)) return false; // Checking if value is alreay there or(||) on recursive call string length should not be provided string
ar.strlen = ar.strlen || str.length; // Setting str length of provided value(string)
ar.push(str); // Pushing to array
for(let i = 0; i<str.length;i++){
str_Permutations(str[i] + str.split('').filter(v=>v!==str[i]).join(''),ar);
}
return Array.from(ar); // Removing *strlen* from main result and return **Result** as array
}
str_Permutations("ABC")
//Result: (6) ["ABC", "BAC", "CBA", "BCA", "ACB", "CAB"]
There is used reference feature of Array to hold the values in same Array by passing. I hope you got my point!!!!
const permut = (str) => {
if (str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : [str];
return str
.split("")
.reduce(
(acc, letter, i) =>
acc.concat(
permut(str.slice(0, i) + str.slice(i + 1)).map((val) => letter + val)
),
[]
);
};
found here
This does the job, recursively
function printPermutations(str, res='') {
if (!str.length){
console.log(res);
}
for (let i = 0; i < str.length; i++) {
let remStr = str.substr(0, i) + str.substr(i + 1);
printPermutations(remStr, res + str.substr(i, 1));
}
}
printPermutations("abc")
// result
// abc, acb, bac, bca, cab, cba
Simple and readable approach but only limited to 3 chars
const stringPermutation = (str) => {
let permutations = [];
for (let i in str) {
for (let j in str) {
for (let k in str) {
if (str[i] !== str[j] && str[j] !== str[k] && str[i] !== str[k]) {
permutations.push(str[i] + str[j] + str[k]);
}
}
}
}
return permutations;
};
console.log(stringPermutation("abc"));
var str = "abcdefgh";
for(let i = 0; i<str.length; i++){
for(let j = i; j<=str.length; j++){
if(i != j){
var out = str.slice(i,j);
console.log(out);
}
}
}
Problem (from Cracking the Coding Interview): Write a method to randomly generate a set of m integers from an array of size n.
Each element must have equal probability of being chosen.
I'm implementing my answer in JS. For the recursive function, the code sometimes returns undefined as one of the elements in the array.
My JS Code
var pickMRecursively = function(A, m, i) {
if (i === undefined) return pickMRecursively(A, m, A.length);
if (i+1 === m) return A.slice(0, m);
if (i + m > m) {
var subset = pickMRecursively(A, m, i-1);
var k = rand(0, i);
if (k < m) subset[k] = A[i];
return subset;
}
return null;
};
Given Java Solution
int[] pickMRecursively(int[] original, int m,int i) {
if (i +1==m){// Basecase
/* return first m elements of original */
} elseif(i+m>m){
int[] subset = pickMRecursively(original, m, i - 1);
int k = random value between 0 and i, inclusive
if(k<m){
subset[k] = original[i]j
}
return subset;
}
return null;
}
I hate these questions because sometime they're often deliberately vague - I'd ask "What type of data is in the array?". But if this is actually a question about randomly re-ordering an array, then in JavaScript, given that arr is an array of numbers, of which some/all might not be integers...
function generateM(arr) {
var hold = [];
var m = [];
var n = arr.length;
var grab;
// clone arr >> hold
while(n--) {
hold[n] = arr[n];
}
n = hold.length;
// select randomly from hold
while(n--) {
grab = hold.splice(Math.floor(Math.random()*n),1)[0];
// ensure integers
m.push(Math.round(grab));
}
return m;
}
The array arr is cloned here to cover scoping issues and to produce a fresh collection, not reorder an existing one.
ADDIT: Alternatively, if this is just asking for a set of m.length random integers generated from an array of n.length, then it doesn't matter what the content of the array actually is and the range of possible (randomly generated) values will be (could be?) 0 - n.length, so...
function generateM(arr, M) {
var aLen = arr.length;
var m = [];
do {
m.push(Math.round(Math.random() * aLen));
} while(M--);
return m;
}
...but that seems like a stupid, pointless challenge. The data in the 'array of size n' is quite important here it seems to me.
I am working with Col A, B & C. Col A contains A-E, Col B Contains 1, a, 3, b, 5 and Col C will be where I will store duplicated information (a and b would go into C1 & C2). Any help would be appreciated. In summary; compare A and B for similarity, output result into C
function appendString() {
var range = SpreadsheetApp.getActiveSheet().getRange("A1:A5");
var range2 = SpreadsheetApp.getActiveSheet().getRange("B1:B5");
var range3 = SpreadsheetApp.getActiveSheet().getRange("C1:C5")
var numRows = range.getNumRows();
var x = 0
// var numCols = range.getNumColumns();
j = 1 // row A
k = 2 // row B
m = 3 // row C
n = 1
// First loop though B
for (var i = 1; i <= numRows; i++) {
// set the current value...
var currentValue = range.getCell(i, j).getValue();
// In the log tell us the current value
Logger.log("Set A:" + currentValue);
// Loops though col B to compare to col A
for (var l = 1; l <= numRows; l++) {
// Sets the current value to compare value
var compareValue = range2.getCell(l, j).getValue();
Logger.log("Set B:" + compareValue)
// If the compareValue and the currentValue (match)
if (compareValue === currentValue) {
Logger.log("MATCHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH");
// We will write the result to col C down one row
for (n; n <= x; n++) {
// this makes it only run once'
range3.setValue(currentValue);
Logger.log("Appending.................");
x = n + 3
}
}
}
}
}
I think your problem statement boils down to this: Fill column C with a list of unique values that appear in both column A and B.
There is a built-in javascript Array method Array.indexOf() that makes it very easy to search for matching elements. As the problem is defined, we want to search in a column, so to use that method we need a column to be represented as an Array. The Range.getValues() method allows us to load a whole range of values at once, and delivers them as a two-dimensional array, with rows as the first dimension. We need columns there, and we can achieve that by a matrix transposition.
So here's what we end up with. There isn't a built-in transpose(), so I've included one. As we search for matches, results are stored in an Array C, using the built-in Array.push() method. Finally, array C is treated as a two-dimensional array, transposed, and written out to the sheet in column C.
function recordMatches() {
var range = SpreadsheetApp.getActiveSheet().getRange("A1:B5");
var data = range.getValues();
// For convenience, we'll transpose the data, so
// we can treat columns as javascript arrays.
var transposed = transpose(data);
var A = transposed[0],
B = transposed[1],
C = [];
// Go through A, looking for matches in B - if found, add match to C
for (var i=0; i < A.length; i++) {
if (B.indexOf(A[i]) !== -1) C.push(A[i]);
}
// If any matches were found, write the resulting array to column C
if (C.length > 0) {
var rangeC = SpreadsheetApp.getActiveSheet().getRange(1,3,C.length);
rangeC.setValues(transpose([C]));
}
}
function transpose(a) {
return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}