How to interweave two arrays in JavaScript? - javascript

I'm super confused with getting this to run, as nested loops are still a bit funny to me.
With the following two arrays:
let a = ['y','y','y'];
let z = ['x','x','x','x','x'];
How do I get it to print one value from a, and then two values from z after that so and so on?
'y',
'x',
'x',
'y',
'x',
'x',
'y',
'x',
'x'
If the values were instead:
let a = ['y','y'];
let z = ['x','x','x','x','x'];
It'd print:
'y',
'x',
'x',
'y',
'x',
'x',
'x'
This is what I've tried so far:
for (let i = 0; i < a.length; i++) {
console.log(a[i]);
for (let j = 0; j < z.length; j++) {
console.log(z[j], z[j+1]);
// break?
}
}

I repair your loop:
let a = ['y','y','y'];
let z = ['x','x','x','x','x'];
for (let i = 0; i < a.length; i++) {
console.log(a[i]);
console.log(z[i*2], z[i*2+1]);
}

`
let a = ['y','y'];
let z = ['x','x','x','x','x'];
let j = 0;
for (let i = 0; i < a.length; i++) {
console.log(a[i]);
for (j; j < z.length; j++) {
console.log(z[j], z[j+1]);
if(j % 2 == 1){
break;
}
}
}`
try this one.

One option you have is to use do/while loop. Use shift() to remove the first item.of an array
let a = ['y1', 'y2', 'y3'];
let z = ['x1', 'x2', 'x3', 'x4', 'x5', 'x6'];
//Copy the array a and z
let aTemp = [...a];
let zTemp = [...z];
do {
if (aTemp.length) console.log(aTemp.shift());
if (zTemp.length) console.log(zTemp.shift());
if (zTemp.length) console.log(zTemp.shift());
} while (aTemp.length || zTemp.length); //Loop while both the temp variables have elements

let aIndex = 0, zIndex = 0;
while(aIndex < a.length || zIndex < z.length) {
console.log(
a[aIndex++],
z[zIndex++],
z[zIndex++]
);
}

Here is non destructive way of doing this
var pointer = 0;
for (let i = 0; i < a.length; i++) {
var count = 0;
console.log(a[i]);
for (let j = pointer; j < z.length; j++) {
console.log(z[j]);
count++;
if(count == 2){
count = 0;
if(i == a.length-1) { continue; }else { pointer = j+1; break; }
}
}
}

let c = j = 0;
z.map(function(item){
if(c === 0 && a[j]){ console.log(a[j++]); }
console.log(item);
c = c > 0 ? 0 : c + 1;
});

Please have a look at the below code. I pushed your expected output result in to an array.
let a = ['y','y'];
let z = ['x', 'x', 'x', 'x', 'x'];
let arr = [];
for (let i = 0; i < a.length; i++) {
var count = 0
arr.push(a[i]);
for (let j = i * 2; j < z.length; j++) {
arr.push(z[j]);
count++
if (count > 1) {
if (z[j+1] !== undefined && a[i+1] === undefined) {
for (let k = j+1; k < z.length; k++) {
arr.push(z[k])
}
}
break;
}
}
}
console.log(arr);
// ["y", "x", "x", "y", "x", "x", "x"]

You don't need a nested loop at all. This can be done with a single loop with two counters.
let a = ['y','y','y'];
let z = ['x','x','x','x','x'];
let result = [];
for(let i = 0, j = 0; i < a.length, j < z.length; i++, j+=2) {
result.push(a[i], z[j], z[j+1]);
}
result = result.filter(item => item !== undefined);
console.log(result);
And here's the same code condensed to a one-liner core:
let a = ['y','y','y'];
let z = ['x','x','x','x','x'];
let result = [];
for(let i = 0, j = 0; i < a.length, j < z.length; i++, j+=2) {
result.push.apply(result, [a[i], z[j], z[j+1]].filter(m => m !== undefined));
}
console.log(result);

You could take the length and calculate the interval/part lenght of the array for splicing and pushing to the result set.
function getX(a, b) {
var iA = Math.ceil(a.length / b.length),
iB = Math.ceil(b.length / a.length),
pA = 0,
pB = 0,
result = [];
while (pA < a.length || pB < b.length) {
result.push(
...a.slice(pA, pA += iA),
...b.slice(pB, pB += iB)
);
}
return result;
}
console.log(getX(['y','y','y'], ['x','x','x','x','x']).join(' '));
console.log(getX(['y','y'], ['x','x','x','x','x']).join(' '));

Here is an example using Array.prototype.reduce() and a destructuring assignment:
let a = ["y", "y", "y"];
let z = ["x", "x", "x", "x", "x"];
let y = a.reduce((acc, current, index) => {
return [...acc, current, ...z.splice(0, a[index + 1] ? 2 : z.length)];
}, []);
console.log(y);
console.log(z);
On every a array element you take previously accumulated array (initially []), add current element and two elements from z if a has next element or the rest of z elements if current is the last element of a.
This unfortunately deletes elements from z in the process, so you might want to copy it before running it, i.e. you can wrap reduce in a function and pass a copy of z:
let a = ["y", "y", "y"];
let z = ["a", "b", "c", "d", "e", "f", "g"];
const interweave = (arr1, arr2) => {
return arr1.reduce((acc, current, index) => {
return [
...acc,
current,
...arr2.splice(0, arr1[index + 1] ? 2 : arr2.length)
];
}, []);
};
console.log(interweave(a, [...z]));
console.log(z);

You can do it without any for or while too! try this:
let a = ['y','y','y'];
let z = ['x','x','x','x','x'];
console.log(
[].concat.apply([], a.map(function(m, i){return [m].concat(z.slice(i*2, i*2+2));}))
);
Now you can join the result if you want like this:
let a = ['y','y','y'];
let z = ['x','x','x','x','x'];
console.log(
[].concat.apply([], a.map(function(m, i){return [m].concat(z.slice(i*2, i*2+2));})).join(",")
);
Or if you like reduce function, you can try this:
let a = ['y','y','y'];
let z = ['x','x','x','x','x'];
console.log(
a.reduce(function(ac, m, i){return ac.push.apply(ac, [m].concat(z.slice(i*2, i*2+2))), ac;}, [])
);

Related

Nested matrix and nested loop problem not working

This should be the input and output:
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [[7,4,1],[8,5,2],[9,6,3]]
The returned output is actually the same as the input. What am I doing wrong?
var rotate = function(matrix) {
let result = matrix;
let i = 0;
let index = matrix.length - 1;
for (let x of matrix) {
for (let n of x) {
result[i][index] == n;
if (i<matrix.length-2)
i++;
}
index--;
}
console.log(result);
return result;
};
var list= [[1,2,3],[4,5,6],[7,8,9]];
rotate(list);
const matrix = [
[1,2,3],
[4,5,6],
[7,8,9]
];
const rotate = (m) => {
const n = m.length;
const r = [ ...m.map(a => []) ];
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
r[i][j] = m[n - j - 1][i];
}
}
return r;
}
const result = rotate(matrix);
console.log(result);

Arrays with elements less or equal to the elements in given array

What is the most JS-style way to solve the following problem?
Given an array A, find all arrays B, such that for i <= A.length: B[i] <= A[i]. Example of what I expect:
#Input
A = [1,2,0]
#Output
B = [[0,0,0],
[1,0,0],
[1,1,0],
[1,2,0],
[0,1,0],
[0,2,0]]
In Python I used:
B = [[]];
for t in [range(e+1) for e in A]:
B = [x+[y] for x in B for y in t]
Thanks in advance!
Use the following code (any loop for one item of the array a):
var a = [1, 2, 0], b = [];
for (var i = 0; i < a[0]; i++) {
for (var j = 0; j < a[1]; j++) {
for (var k = 0; k <= a[2]; k++) {
b.push([i, j, k]);
}
}
}
If you know the numebr of items in the array a only on runtime, use the following recursive function:
function fillArray(source, dest, recursionLevel, tempArr) {
if (recursionLevel >= source.length) {
dest.push(tempArr);
return;
}
for (var i = 0; i <= source[recursionLevel]; i++) {
var tempArr2 = tempArr.slice(); // Copy tempArr
tempArr2.push(i);
fillArray(source, dest, recursionLevel + 1, tempArr2);
}
}
fillArray(a, b, 0, []);
I found this solution. I'm sure it can be coded in a much nicer way. However, it works and I hope you find it useful
all_combinations(A){
var B = [];
for (var i = 0; i < A[0] + 1; i++) {
B.push([i]);
}
for (var i = 1; i < A.length; i++) {
var _tmp_array = [];
for (var j = 0; j < A[i] + 1; j++) {
for (var k = 0; k < B.length; k++) {
var _new_element = B[k].concat([j]);
_tmp_array.push(_new_element);
}
}
B = _tmp_array;
}
return B;
}

Replace an element in an array

Need to replace a value "y" with "#" in an array and also need to count the "y" value in an array.
x = ['a','b','c'];
z = ['z','y','y'];
var a = x.concat(z);
var b = a.sort();
var count = 0;
for(var i = 0; i < b.length; i++){
if(b[i] == "y") {
b['y'] == "#";
var c = count++;
}
}
console.log(b);
console.log(c+1);
Fiddle
declare all variables
assign the right value, do not make a comparison b[i] = "#";,
use count variable, and not c
no need to use b, because sort sorts the given array.
var x = ['a', 'b', 'c'];
var z = ['z', 'y', 'y'];
var a = x.concat(z);
var count = 0;
a.sort();
for (var i = 0; i < a.length; i++){
if (a[i] == "y") {
a[i] = "#";
count++;
}
}
console.log(a);
console.log(count);
You can use reduce with destructuring assignment to effectively return 2 values
var x = ['a','b','c']
var z = ['z','y','y']
var a = x.concat(z)
var [count, b] = a.reduce(([count,b],x)=> {
if (x === 'y')
return [count + 1, [...b, '#']]
else
return [count, [...b, x]]
}, [0, []])
console.log(count) // 2
console.log(b) // ['a', 'b', 'c', 'z', '#', '#']
If you really want the array sorted before replacing 'y' and getting the count, you should know that Array.prototype.sort will mutate the original array. Also, assignment of an array to a variable is by reference.
So when you write this...
var b = a.sort();
You should know that a will be sorted, and b is just a second reference to the exact same array. b is not a separate copy.
If you'd like to make a separate copy, you can do this
// make B a sorted copy of A. do not modify A.
var b = a.slice(0).sort();
== is comparison operator
= is assignment operator
Change to this :
for(var i = 0; i < b.length; i++){
if(b[i] == "y") {
b[i] = "#";
var c = count++;
}
}
from
for(var i = 0; i < b.length; i++){
if(b[i] == "y") {
b['y'] == "#";
count++;
}
}
x = ['a', 'b', 'c'];
z = ['z', 'y', 'y'];
var a = x.concat(z);
var b = a.sort();
var count = 0;
for (var i = 0; i < b.length; i++) {
if (b[i] == "y") {
b[i] = "#";
count++;
}
}
console.log(b);
console.log(count);
You can also use Array#map.
var x = ['a','b','c'];
var z = ['z','y','y'];
var a = x.concat(z);
var b = a.sort();
var count = 0;
b = b.map(function(v) {
if(v == 'y') {
count++;
return '#';
} else {
return v;
}
});
console.log(b);
console.log(count);
I'm not sure, but is this what you want?
x = ['a','b','c'];
z = ['z','y','y'];
var a = x.concat(z);
var b = a.sort();
var count = 0;
for(var i = 0; i < b.length; i++){
if(b[i] == "y") {
b[i] = "#";
var c = count++;
}
}
console.log(b);
console.log(c+1);
jsfiddle
If you are the fan of less line of code, then this one line (or maybe two line) implementation would be noticeable. ;)
BUT the main reason of my answer was about the sort return value.
as mentioned in documentation:
The sort() method sorts the elements of an array in place and returns
the array. The sort is not necessarily stable. The default sort order
is according to string Unicode code points.
So the sort() method do the action in place and returns the result (the array) too.
var x = ['a', 'b', 'c'],
z = ['z', 'y', 'y'],
toReplace = 'y',
replaceWith = '#',
count = 0;
var result = x.concat(z).sort()
.map((v, i, a) => v === toReplace ? ++count && replaceWith : v);
console.log(result, count);

Generating all possible combinations of strings

I am trying to generate all possible combinations of a string.
e.g. for the list below: a1q5z!H9, b1q5z!H9, c1q5z!H9, d1q5z!H9, a2q5z!H9 ... etc
Rather than make lots of nested loops, I thought I would try something clever with MODULO ... but hit a wall.
This is the Javascript I have come up with - any pointers to how I might go on?
var c = [
['a', 'b', 'c', 'd'],
['1', '2', '3', '4'],
['q', 'w', 'e', 'r'],
['5', '6', '7', '8'],
['z', 'x', 'c', 'v'],
['!', '"', '£', '$'],
['H', 'J', 'K', 'L'],
['9', '8', '7', '6'],
];
var o = document.getElementById('output');
var pw = "";
var chars = c.length;
for( var i = 0; i <20; i++)
{
pw = ""
for(var j = 0; j < chars; j++ )
{
pw += c[j][i%4];
}
op(pw);
}
function op(s)
{
o.innerHTML = o.innerHTML + "<br>" + s;
}
This just outputs the first 20 in the list, but repeats ... I nearly have it but not quite. Any help or pointers appreciated.
Quite easy to write a recursive function demo.
function permutate(abc, memo) {
var options;
memo = memo || abc.shift().slice(0);
if(abc.length) {
options = abc.shift();
return permutate(abc, memo.reduce(function(all, item){
return all.concat(options.map(function(option){
return item + option;
}))
}, []));
}
return memo;
};
console.log(permutate(c).length); //65536 items
Or more imperative approach
function permutate2(abc) {
var options, i, len, tmp, j, optionsLen,
memo = abc.pop().slice(0); //copy first the last array
while(options = abc.pop()) { //replace recursion
tmp = [];
optionsLen = options.length;
for(i = 0, len = memo.length; i < len; i++) { //for every element in memo
for(j = 0; j < optionsLen; j++) { //do cartesian product with options
tmp.push(options[j] + memo[i]);
}
}
memo = tmp;
}
return memo;
}
function combinations(str) {
debugger;
var arr = [];
for (var i = 0; i < str.length; i++)
{
// create an empty string
var comb = "";
// loop for substring
for (var j = i; j < str.length; j++)
{
comb+=str[j];
arr.push(comb);
}
}
return arr;
}
console.log(combinations('output'));
This is how I did it:
string password;
bool done = false;
while (!done) {
password = string.Empty;
for(int a = 0; a < blah[0].Length; a++) {
for(int b = 0; b < blah[1].Length; b++) {
for (int c = 0; c < blah[2].Length; c++) {
for (int d= 0; d < blah[3].Length; d++) {
for (int e = 0; e < blah[4].Length; e++) {
for (int f = 0; f < blah[5].Length; f++) {
for (int g = 0; g < blah[6].Length; g++) {
for (int h = 0; h < blah[7].Length; h++) {
password = string.Format(
"{0}{1}{2}{3}{4}{5}{6}{7}",
blah[0][a],
blah[1][b],
blah[2][c],
blah[3][d],
blah[4][e],
blah[5][f],
blah[6][g],
blah[7][h]);
Console.Out.WriteLine(password);
}
}
}
}
}
}
}
}
}
Where blah is the character matrix.
Ugly, granted, but the shorter answer by Yury hurts my head.

How to merging javascript arrays and order by position?

Is there anyway to merge arrays in javascript by ordering by index/position. I'm try to accomplish this and haven't been able to find any examples of this.
var array1 = [1,2,3,4]
var array2 = [a,b,c,d]
var array3 = [!,#,#,$]
var merged array = [1,a,!,2,b,#,3,c,#,4,d,$]
I know you can use concat() to put one after the other.
As long as the arrays are all the same length you could just do:
var mergedArray = [];
for (var i = 0, il = array1.length; i < il; i++) {
mergedArray.push(array1[i]);
mergedArray.push(array2[i]);
mergedArray.push(array3[i]);
}
EDIT:
For arrays of varying lengths you could do:
var mergedArray = [];
for (var i = 0, il = Math.max(array1.length, array2.length, array3.length);
i < il; i++) {
if (array1[i]) { mergedArray.push(array1[i]); }
if (array2[i]) { mergedArray.push(array2[i]); }
if (array3[i]) { mergedArray.push(array3[i]); }
}
This should work for arrays of ANY length:
var mergeArrays = function () {
var arr = [],
args = arr.slice.call(arguments),
length = 0;
for (var i = 0, len = args.length; i < len; i++) {
length = args[i].length > length ? args[i].length : length;
}
for (i = 0; i < length; i++) {
for (var j = 0; j < len; j++) {
var value = args[j][i];
if (value) {
arr.push(value);
}
}
}
return arr;
};
Example:
var array1 = [1,2,3,4];
var array2 = ['a','b','c','d','e','f','g','h','i','j','k','l'];
var array3 = ['!','#','#','$','%','^','&','*','('];
mergeArrays(array1, array2, array3);
// outputs: [1, "a", "!", 2, "b", "#", 3, "c", "#", 4, "d", "$", "e", "%", "f", "^", "g", "&", "h", "*", "i", "(", "j", "k", "l"]
This would work also (a little more terse syntax):
var mergeArrays = function () {
var arr = [],
args = arr.slice.call(arguments),
length = Math.max.apply(null, args.map(function (a) { return a.length; }));
for (i = 0; i < length; i++) {
for (var j = 0, len = args.length; j < len; j++) {
var value = args[j][i];
if (value) {
arr.push(value);
}
}
}
return arr;
};
For arrays that are all the same size, where you pass one or more arrays as parameters to merge:
function merge()
{
var result = [];
for (var i=0; i<arguments[0].length; i++)
{
for (var j=0; j<arguments.length; j++)
{
result.push(arguments[j][i]);
}
}
return result;
}
var array1 = ['1','2','3','4'];
var array2 = ['a','b','c','d'];
var array3 = ['!','#','#','$'];
var merged = merge(array1, array2, array3);
Nothing built in, but it wouldn't be hard to manage:
var maxLength = Math.max(array1.length, array2.length, array3.length),
output = [];
for (var i = 0; i < maxLength; i++) {
if (array1[i] != undefined) output.push(array1[i]);
if (array2[i] != undefined) output.push(array2[i]);
if (array3[i] != undefined) output.push(array3[i]);
}
try this...
var masterList = new Array();
var array1 = [1,2,3,4];
var array2 = [a,b,c,d];
var array3 = [!,#,#,$];
for(i = 0; i < array1.length; i++) {
masterList.push(array1[i]);
masterList.push(array2[i]);
masterList.push(array3[i]);
}
It looks like you want to "zip" some number of same-length arrays into a single array:
var zip = function() {
var numArrays=arguments.length
, len=arguments[0].length
, arr=[], i, j;
for (i=0; i<len; i++) {
for (j=0; j<numArrays; j++) {
arr.push(arguments[j][i]);
}
}
return arr;
};
zip([1,2], ['a', 'b']); // => [1, 'a', 2, 'b']
zip([1,2,3], ['a','b','c'], ['!','#','#']); // => [1,'a','#',...,3,'c','#']
If the input arrays could be of different length then you've got to figure out how to deal with that case...
Yes, there is some way to do that. Just:
loop through the larger array,
until at the currently processed position both arrays have elements, assign them one-by-one to the new array,
after the shorter array ends, assign only elements from the longer array,
The resulting array will have the elements ordered by the index from the original arrays. From your decision depends, position in which one of these arrays will have higher priority.
This works for any number of array and with arrays of any length.
function myMerge() {
var result = [],
maxLength = 0;
for (var i = 0; i < arguments.length; i++) {
if (arguments[i].length > maxLength) { maxLength = arguments[i].length; }
}
for (var i = 0; i < maxLength; i++) {
for (var j = 0; j < arguments.length; j++) {
if (arguments[j].length > i) {
result.push(arguments[j][i]);
}
}
}
return result;
}
Eli beat me to the punch up there.
var posConcat = function() {
var arrays = Array.prototype.slice.call(arguments, 0),
newArray = [];
while(arrays.some(notEmpty)) {
for(var i = 0; i < arrays.length; i++) {
if(arguments[i].length > 0)
newArray.push(arguments[i].shift());
}
}
return newArray;
},
notEmpty = function() { return arguments[0].length > 0; };
Usage:
var orderedArray = posConcat(array1,array2,array3);
Sample: http://jsfiddle.net/HH9SR/

Categories