I am trying to iterate over the original string 3 times. The result I get is:
["a","b","c","d",undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined]
The correct result should be: ["a", "b", "c", "d", "a", "b", "c", "d", "a", "b", "c", "d"]
function makeCopies (str, howmany) {
let newCopy = [];
for(let i = 0; i < str.length * howmany; i++) {
newCopy.push(str[i])
}
return newCopy;
}
console.log(makeCopies("abcd", 3))
I have tried many variations but nothing works, this is the closest I got.
JavaScript has a repeat Method on Strings. You can just use "abcd".repeat(3) and you will get "abcdabcdabcd". If you really want an array of the chars, you can spread the string into an array with [..."abcd".repeat(3)].
Javascript has a nice utility for this String.prototype.repeat. You can then split it on every character if an array is what you want.
console.log("abcd".repeat(3).split(""))
The length of the array is becoming 12 when you multiply str.length * howmany, and when it gets further than the fourth value it can't find anything and so becomes undefined.
A solution is you can wrap the main loop in another loop which will run howmany times.
function makeCopies (str, howmany) {
let newCopy = [];
for (let i = 0; i < howmany; i++) {
for(let j = 0; j < str.length; j++) {
newCopy.push(str[j])
}
}
return newCopy;
}
console.log(makeCopies("abcd", 3))
const makeCopies = (string, count) => new Array(count).join(string).split('');
console.log(makeCopies('abcd', 4))
Why don’t you use repeat() ?
const res = "abc".repeat(3); // abcabcabc
If you need it as array, you can:
res.split(""); // ["a", "b", "c", ...]
You are iterating outside the bounds of original string
str[i]; // i < str.length * howmany;
Try create two cycles instead:
for(let i = 0; i < howmany; i++) {
for(let j = 0; j < str.length; j++) {
newCopy.push(str[j])
}
}
Related
I am trying to combine items in an array, with every item below it. It should make a set of the current character and each character below it, and iteratively walk down the array. For example, if I have an array like this:
var myArray = ['A','B','C','D']
I would like an output like this:
AB AC AD BC BD CD
The code I have is getting me close, but I am having a hard time figuring out the rest. Here is what I have so far:
var myArray = ['A', 'B', 'C', 'D']
var sql_parts = []
var string = "";
for (var i = 0; i < myArray.length; i++) {
recurse_function(string, i)
}
console.log(sql_parts)
function recurse_function(string_val, count) {
if ((myArray.length - count) == 0) {
return string_val;
} else {
string_val += myArray[count]
sql_parts.push(string_val)
recurse_function(string_val, count + 1)
}
}
But this produces:
["A", "AB", "ABC", "ABCD", "B", "BC", "BCD", "C", "CD", "D"]
Here is one solution:
Define the recursive function to take the array and an empty list initially to store the combinations
The base condition is when the array is empty or has one element
Otherwise, Remove the first element "start"
Iterate over the array to store its combinations with its following elements
Recur again with array and combinations updated
function recurse_function(array, combinations = []) {
if(array.length <= 1) return combinations;
const start = array.shift();
for(let i = 0; i < array.length; i++) combinations.push(`${start}${array[i]}`);
return recurse_function(array, combinations);
}
console.log( recurse_function(['A','B','C','D']) );
var myArray = ['A','B','C','D']
var sql_parts = []
for(var i =0; i< myArray.length; i++){
var a = myArray[i]
for(var j = i+1; j<myArray.length; j++){
var b=myArray[j]
var c= a+b
sql_parts.push(c)
}
}
I think this is something that you're looking for, it's a function that is very cheap on resources. Its not recursive (why you now would need something like that for this simple scenario)
var myArray = ['A','B','C','D']
let [a, b, iter] = [0, 1, 2]
let result = []
for (;a < myArray.length; a++) {
for (;b < myArray.length; b++) {
result.push(myArray[a]+myArray[b])
}
b = iter++
}
console.log(result)
I don't think you need to recurse in this particular case. You can simply combine the current element with the following ones with flatMap:
['A','B','C','D'].flatMap((x, i, xs) => xs.slice(i+1).map(y => x+y));
//=> ["AB", "AC", "AD", "BC", "BD", "CD"]
var myArray = ['A', 'B', 'C', 'D'];
var result = [];
myArray.forEach((item, index) => {
myArray.forEach((item2, index2) => (index < index2 ? result.push(item + item2) : ''));
});
console.log(result);
Quick JavScript question. In the following pieces of code I'm reversing the array arr that's being passed to the function reverseArray.
In the first piece of code, it looks like that the local variable arr keeps changing even though inside the loop I am operating on the variable newArr which hold the initial value of arr. Hence the loop fails when arr.length reaches the values 3.
function reverseArray (arr) {
var newArr = [];
var inArr = arr;
console.log(inArr);
for (i = 0; i < arr.length; i++) {
newArr[i] = inArr.pop(i);
}
return newArr;
}
reverseArray(["A", "B", "C", "D", "E", "F"]);
// OUTPUT: ["F", "D", "E"]
On the other hand, if I store arr.length on local variable numArr, then it works perfectly and reverses the array.
function reverseArray (arr) {
var numArr = arr.length;
var newArr = [];
for (i = 0; i < numArr; i++) {
let inArr = arr;
newArr[i] = inArr.pop(i);
}
return newArr;
}
reverseArray(["A", "B", "C", "D", "E", "F"]);
// OUTPUT: ["F", "E", "D", "C", "B", "A"]
What am I missing?
pop (MDN, spec) is a mutator method: It changes the state of the array you call it on. So naturally, inArr.pop(1) modifies arr (in your first example), since inArr and arr both refer to the same array.
Probably worth noting as well that pop doesn't accept any parameters, so that 1 doesn't do anything.
In your first example, your best bet is to just assign another variable (say, j) the initial value arr.length - 1 and use arr[j] to get the value, then decrease j as you increase i. (Also, no point to inArr, and you need to declare i to avoid what I call The Horror of Implicit Globals:
function reverseArray (arr) {
var newArr = [];
for (var i = 0, j = arr.length - 1; i < arr.length; i++, j--) {
newArr[i] = arr[j];
}
return newArr;
}
console.log(reverseArray(["A", "B", "C", "D", "E", "F"]));
You can also just use arr[arr.length - i - 1] rather than a second variable:
function reverseArray (arr) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
newArr[i] = arr[arr.length - i - 1];
}
return newArr;
}
console.log(reverseArray(["A", "B", "C", "D", "E", "F"]));
You could take a copy of the array and use the length of the copy for checking the next pop/push command.
function reverseArray(array) {
var newArr = [],
inArr = array.slice(); // take copy of primitive values
while (inArr.length) { // check decrementing length
newArr.push(inArr.pop());
}
return newArr;
}
console.log(reverseArray(["A", "B", "C", "D", "E", "F"]));
To fullfill the condition, you could use a for statement as well.
function reverseArray(array) {
var newArr = [],
inArr = array.slice(); // take copy of primitive values
for(; inArr.length; ) { // check decrementing length
newArr.push(inArr.pop());
}
return newArr;
}
console.log(reverseArray(["A", "B", "C", "D", "E", "F"]));
Here It Goes using two For Loops:
let arr = [1, 12, 15, 16, 78, 89, 53];
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
let c, a, b;
b = arr[i];
arr[i] = arr[j];
arr[j] = b;
}
}
console.log(arr);
Example:
fruit=['banana', 'orange', 'mango', 'lemon'] //array
z=[] //empty array
for(i=(fruit.length-1);i>-1;i--){
z.push(fruit[i])
}
//i>-1 because the index of array ends at 0
console.log(z)
The problem with your first function is that when you pop an element from an array arr its actually decreasing the length of your array arr. That is why you see less results then the original number of elements.
so your code worked like this
1st pass: i=0 and arr.length = 6; // 0<6 true
2nd pass: i=1 and arr.length = 5; // 1<5 true
3rd pass: i=2 and arr.length = 4; // 2<4 true
4th pass: i=3 and arr.length = 3; // 3<3 false and it does not execute
so you see only three results.
let input = ["A", "B", "C", "D", "E", "F"];
let output = [];
for(let i = 1; i <= input.length; i++) {
// determine correct array index in respect to the current iteration
let index = input.length - i;
// push to new array
output.push(reverse[index]);
}
// verify result
console.log(output);
This is similar code to reverse an Array.
function reverseArray(arr) {
let newArr = [];
for (i = arr.length - 1; i >= 0; i--) {
newArr.push(arr[i]);
}
return newArr;
}
console.log(reverseArray(["A", "B", "C", "D", "E", "F"]));
//output: ["F","E","D","C","B","A"]
function reverseArray(a) {
let arrayLength = a.length
for (let i = 0; i< arrayLength/2; i ++){
let temp = a[i]
a[i] = a[arrayLength -(i+1)]
a[arrayLength - (i+1)] = temp
}
return a
}
reverseArray([1,2,3,4,5,6,7,8,9]) //expect: 9,8,7,6,5,4,3,2,1
You could try to use this code:
function reverseString(str) {
var newString = "";
for (var i = str.length - 1; i >= 0; i--) {
newString += str[i];
}
return newString;
}
Given an array or object with n keys, I need to find all combinations with length x.
Given X is variable. binomial_coefficient(n,x).
Currently I'm using this:
function combine(items) {
var result = [];
var f = function(prefix, items) {
for (var i = 0; i < items.length; i++) {
result.push(prefix + items[i]);
f(prefix + items[i], items.slice(i + 1));
}
}
f('', items);
return result;
}
var combinations = combine(["a", "b", "c", "d"]);
The output is:
["a", "ab", "abc", "abcd", "abd", "ac", "acd", "ad", "b", "bc", "bcd", "bd", "c", "cd", "d"]
So if I want the binomial coefficient x=3 from n=4 I select all the strings with length equal to three. {abc, abd, acd, bcd}.
So I do this in two steps.
Is there a more efficient algorithm with smaller complexity?
Link: Solution performance (JSPerf)
Your algorithm is almost O(2^n), you can discard a lot of combinations, but the num of elements will be (n! * (n-x)!) / x!.
To discard the useless combinations you can use an indexed array.
function combine(items, numSubItems) {
var result = [];
var indexes = new Array(numSubItems);
for (var i = 0 ; i < numSubItems; i++) {
indexes[i] = i;
}
while (indexes[0] < (items.length - numSubItems + 1)) {
var v = [];
for (var i = 0 ; i < numSubItems; i++) {
v.push(items[indexes[i]]);
}
result.push(v);
indexes[numSubItems - 1]++;
var l = numSubItems - 1; // reference always is the last position at beginning
while ( (indexes[numSubItems - 1] >= items.length) && (indexes[0] < items.length - numSubItems + 1)) {
l--; // the last position is reached
indexes[l]++;
for (var i = l +1 ; i < numSubItems; i++) {
indexes[i] = indexes[l] + (i - l);
}
}
}
return result;
}
var combinations = combine(["a", "b", "c", "d"], 3);
console.log(JSON.stringify(combinations));
For example, the first combination have the indexes: [0, 1, 2] and the elements ["a", "b", "c"]. To compute the next combination, It get the last index 2 and try to increment, if the increment is lower than the max position (in this case 4), the next combination is reached, but if It is not, It must increment to a previous index.
You could use an iterative and recursive approach with stress on the length of the array and the still needed items.
Basically combine() takes an array with the values to combine and a size of the wanted combination results sets.
The inner function c() takes an array of previously made combinations and a start value as index of the original array for combination. The return is an array with all made combinations.
The first call is allways c([], 0), because of an empty result array and a start index of 0.
function combine(array, size) {
function c(part, start) {
var result = [], i, l, p;
for (i = start, l = array.length; i < l; i++) {
p = part.slice(0); // get a copy of part
p.push(array[i]); // add the iterated element to p
if (p.length < size) { // test if recursion can go on
result = result.concat(c(p, i + 1)); // call c again & concat rresult
} else {
result.push(p); // push p to result, stop recursion
}
}
return result;
}
return c([], 0);
}
console.log(combine(["a", "b", "c", "d"], 3));
.as-console-wrapper { max-height: 100% !important; top: 0; }
We could create just those combinations we are interested in. Also, rather than cloning arrays by using slice in each call, we can use a pointer to the original array. Here's one version. Converting it to recursion without an external global variable is left as an exercise.
function choose(ns,r){
var res = [];
function _choose(i,_res){
if (_res.length == r){
res.push(_res);
return;
} else if (_res.length + ns.length - i == r){
_res = _res.concat(ns.slice(i));
res.push(_res);
return
}
var temp = _res.slice();
temp.push(ns[i]);
_choose(i + 1,temp);
_choose(i + 1,_res);
}
_choose(0,[]);
return res;
}
var combinations = choose(["a", "b", "c", "d"], 3);
console.log(JSON.stringify(combinations));
And here's the true recursion.
function seq(a,b){
var res = [];
for (var i=a; i<=b; i++)
res.push(i);
return res;
}
function f(n,k){
if (k === 0)
return [[]];
if (n === k)
return [seq(1,n)];
let left = f(n - 1, k - 1),
right = f(n - 1, k);
for (let i=0; i<left.length; i++)
left[i].push(n);
return left.concat(right);
}
console.log(JSON.stringify(f(4,3)))
Doing a freeCodeCamp challenge called "Chunky Monkey". The objective is to create a function that takes two parameters: a 1D array and a number for size.
The array is to be split into a number of groups of the length size (up to that number), thus creating a 2D array.
In my first attempt, my code was:
function chunkArrayInGroups(arr, size) {
var set = arr.length / size;
var count = 0;
set = Math.ceil(set); //ensure that an integer is obtained
var array = [];
for (var i = 0; i < set; i++) {
array[i] = []; //ensure each element i is an array
for (var j = 0; j < size; j++) {
array[i][j] = arr[count]; //obtain values from passed array, arr
count++;
}
}
return array;
}
var result = chunkArrayInGroups(["a", "b", "c", "d"], 2);
console.log(result);
I have traced this code a few times, but I cannot tell why it is wrong. Can someone please spot the error in it?
I eventually tackled the problem using a slightly different method, and it worked, but I am very interested in why the code above did not work.
You need to break the loop once count reach the max limit:
function chunkArrayInGroups(arr, size) {
var set = arr.length/size;
var count = 0;
set = Math.ceil(set); //ensure that an integer is obtained
var array = [];
out:
for(var i = 0; i<set; i++){
array[i] = []; //ensure each element i is an array
for (var j=0; j<size; j++){
if (count === arr.length) {
break out;
}
array[i][j] = arr[count]; //obtain values from passed array, arr
count++;
}
}
return array;
}
var result = chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 4);
console.log(result);
The code is working (with some exceptions, see result of console.log( chunkArrayInGroups(["a", "b", "c", "d"], 5) ); and #shaochuancs answer), but you may try a simpler approach utilizing native methods, like (see chunk function):
function chunkArrayInGroups(arr, size) {
var set = arr.length/size;
var count = 0;
set = Math.ceil(set); //ensure that an integer is obtained
var array = [];
for(var i = 0; i<set; i++){
array[i] = []; //ensure each element i is an array
for (var j=0; j<size; j++){
array[i][j] = arr[count]; //obtain values from passed array, arr
count++;
}
}
return array;
}
function chunk( arr, size ) {
var chunkedArray = [];
while ( arr.length > 0 ) {
chunkedArray.push( arr.splice( 0, size ) );
}
return chunkedArray;
}
console.log( chunkArrayInGroups(["a", "b", "c", "d"], 2) );
console.log( chunkArrayInGroups(["a", "b", "c", "d"], 5) );
console.log( chunkArrayInGroups([], 2) );
console.log( chunk(["a", "b", "c", "d"], 2) );
console.log( chunk(["a", "b", "c", "d"], 5) );
console.log( chunk([], 2) );
I have an array like [A,B,C,D]. I want to access that array within a for loop like as
var arr = [A,B,C,D];
var len = arr.length;
for(var i = 0; i<len; i++){
0 - A,B,C
1 - B,C,D
2 - C,D,A
3 - D,A,B
}
I want to access that like in JavaScript, any ideas?
Answering to the main question, someone can access an array in a circular manner using modular arithmetic. That can be achieved in JavaScript with the modulus operator (%) and a workaround.
Given an array arr of a length n and a value val stored in it that will be obtained through an access index i, the circular manner, and safer way, to access the array, disregarding the value and sign of i, would be:
let val = arr[(i % n + n) % n];
This little trick is necessary -- someone can not use the modulus result straightforwardly -- because JavaScript always evaluates a modulus operation as the remainder of the division between dividend (the first operand) and divisor (the second operand) disconsidering their signs but assigning to the remainder the sign of the dividend. That behavior does not always result in the desired "wrap around" effect of the modular arithmetic and could result in a wrong access of a negative position of the array.
References for more information:
https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/what-is-modular-arithmetic
https://en.wikipedia.org/wiki/Modular_arithmetic
https://en.wikipedia.org/wiki/Modulo_operation
https://dev.to/maurobringolf/a-neat-trick-to-compute-modulo-of-negative-numbers-111e
Try this:
var arr = ["A","B","C","D"];
for (var i=0, len=arr.length; i<len; i++) {
alert(arr.slice(0, 3).join(","));
arr.push(arr.shift());
}
Without mutating the array, it would be
for (var i=0, len=arr.length; i<len; i++) {
var str = arr[i];
for (var j=1; j<3; j++)
str += ","+arr[(i+j)%len]; // you could push to an array as well
alert(str);
}
// or
for (var i=0, len=arr.length; i<len; i++)
alert(arr.slice(i, i+3).concat(arr.slice(0, Math.max(i+3-len, 0)).join(","));
Simply using modulus operator you can access array in circular manner.
var arr = ['A', 'B', 'C', 'D'];
for (var i = 0, len = arr.length; i < len; i++) {
for (var j = 0; j < 3; j++) {
console.log(arr[(i + j) % len])
}
console.log('****')
}
how about this one-liner I made ?
var nextItem = (list.indexOf(currentItem) < list.length - 1)
? list[list.indexOf(currentItem) + 1] : list[0];
for (var i = 0; i < arr.length; i++) {
var subarr = [];
for (var j = 0; j < 3; j++) {
subarr.push(arr[(i+j) % arr.length]);
}
console.log(i + " - " + subarr.join(','));
}
One line solution for "in place" circular shift:
const arr = ["A","B","C","D"];
arr.forEach((x,i,t) => {console.log(i,t); t.push(t.shift());});
console.log("end of cycle", arr); // control: cycled back to the original
logs:
0 Array ["A", "B", "C", "D"]
1 Array ["B", "C", "D", "A"]
2 Array ["C", "D", "A", "B"]
3 Array ["D", "A", "B", "C"]
"end of cycle" Array ["A", "B", "C", "D"]
If you want only the first 3 items, use:
arr.forEach((x,i,t) => {console.log(i,t.slice(0, 3)); t.push(t.shift());});
Another solutions:
var arr = ['A','B','C','D'];
var nextVal = function (arr) {
return arr[( ( ( nextVal.counter < ( arr.length - 1 ) ) ? ++nextVal.counter : nextVal.counter=0 ) )];
};
for(var i=0;i<arr.length;i++){
console.log(nextVal(arr)+','+nextVal(arr)+','+nextVal(arr));
}
And based on Modulo :
var arr = ['A','B','C','D'];
var len = arr.length;
var nextVal = function (arr, dir = 1) {
if ( dir < 0 ) { nextVal.counter--;}
let i = (nextVal.counter % len + len) % len;
if ( dir > 0 ) { nextVal.counter++; }
return arr[i];
};
nextVal.counter=0;
for(var i=0;i<arr.length;i++){
console.log(nextVal(arr)+','+nextVal(arr)+','+nextVal(arr));
}
// in reverse
console.log('-------------------');
nextVal.counter=0;
for(var i=0; i<10; i++) {
console.log(nextVal(arr, -1)+','+nextVal(arr, -1)+','+nextVal(arr, -1));
}
You could get the sliced part from index and the rest of slicing from start, if necessary.
This appraoch does not mutate the array.
const
getCircular = (array, size) => array.map((_, i, a) => [
...a.slice(i, i + size),
...a.slice(0, i + size < a.length ? 0 : i + size - array.length)
]);
console.log(getCircular(['A', 'B', 'C', 'D'], 3).map(a => a.join('')));
console.log(getCircular(['A', 'B', 'C', 'D'], 5).map(a => a.join('')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
We can simply achieve this by using Array.splice() method along with the Destructuring assignment
Live Demo :
// Input array.
let arr = ['A', 'B', 'C', 'D'];
// Finding the length of an array.
const len = arr.length;
// Iterattion based on array length.
for(let i = 0; i < len; i++) {
const splittedArr = arr.splice(0, 3);
arr.push(splittedArr[0]);
arr = [splittedArr[1], splittedArr[2], ...arr]
console.log(splittedArr);
}