JavaScript mutating arrays in loop - javascript

I want to duplicate certain arrays in arrays using JavaScript, for example:
var res = [["1,2,3",100,50],["4,5",75,10],["6",20,90]];
var res2 = [];
for(var z in res) {
var row = res[z];
var keys = row[0].split(',')
for(var y in keys) {
var key = keys[y];
res2.push([key,row[1]/keys.length,row[2]/keys.length]);
}
}
/*
[ [ '1', 33.333333333333336, 16.666666666666668 ],
[ '2', 33.333333333333336, 16.666666666666668 ],
[ '3', 33.333333333333336, 16.666666666666668 ],
[ '4', 37.5, 5 ],
[ '5', 37.5, 5 ],
[ '6', 20, 90 ] ]
*/
The arrays are really-really long, is it possible to do this in-place (res, without res2)?

You can use splice for a true in-place processing of res:
for (var i = 0; i < res.length; ) {
var row = res[i];
var keys = row[0].split(',')
res.splice(i, 1); // Remove old element
// Insert new elements at current position
for (var j in keys)
res.splice(i++, 0, [keys[j], row[1] / keys.length, row[2] / keys.length]);
}
Result:
[
["1", 33.333333333333336, 16.666666666666668],
["2", 33.333333333333336, 16.666666666666668],
["3", 33.333333333333336, 16.666666666666668],
["4", 37.5, 5],
["5", 37.5, 5],
["6", 20, 90]
]
EDIT:
Another trick to avoid splices is to extend the size of res and start filling it from the end to the beginning:
var n = res.length;
// Precalculate new length
var length = 0;
for (var i = 0; i < res.length; i++)
length += res[i][0].split(',').length;
// Change length of array
res.length = length;
// Start filling from end to start
for (var i = n - 1, k = length - 1; i >= 0; i--) {
var row = res[i];
var keys = row[0].split(',');
for (var j = keys.length - 1; j >= 0; j--)
res[k--] = [keys[j], row[1] / keys.length, row[2] / keys.length];
}

You can use reduce function something like this
var res = [["1,2,3",100,50],["4,5",75,10],["6",20,90]];
var r = res.reduce(function(acc,curr){
return acc.concat(curr[0].split(',').map(function(el,_,cursplit){
return [el, curr[1]/cursplit.length,curr[2]/cursplit.length];
}));
},[]);
but i'm not sure that it more readable
var res = [["1,2,3",100,50],["4,5",75,10],["6",20,90]];
var r = res.reduce(function(acc,curr){
return acc.concat(curr[0].split(',').map(function(el,_,cursplit){
return [el, curr[1]/cursplit.length,curr[2]/cursplit.length];
}));
},[]);
document.getElementById('d').innerHTML = r.join('<br>');
<div id="d"></div>
UPDATE
another variant with mutate res
for(var i=0,len=res.length;i<len;i++){
var cur = res.shift();
cur[0].split(',').forEach(function(el,_,cursplit){
res.push([el, cur[1]/cursplit.length,cur[2]/cursplit.length]);
});
}
var res = [["1,2,3",100,50],["4,5",75,10],["6",20,90]];
for(var i=0,len=res.length;i<len;i++){
var cur = res.shift();
cur[0].split(',').forEach(function(el,_,cursplit){
res.push([el, cur[1]/cursplit.length,cur[2]/cursplit.length]);
});
}
document.getElementById('d').innerHTML = res.join('<br>');
<div id="d"></div>

You can get it with Array.reduce
var res = [["1,2,3",100,50],["4,5",75,10],["6",20,90]];
res = res.reduce(function(a, b){
var parts = b[0].split(',');
parts.forEach(function(i){
a.push([i, b[1]/parts.length, b[2]/parts.length]);
});
return a;
}, []);
But, I believe this still eat double memory :)
Another solution (with res2, but more economy):
It get source entities one-by-one, process it and gc allowed to clean memory...
var res2 = [];
while (res.length) {
var cur = res.shift();
var ids = cur[0].split(',')
ids.forEach(function(i){
res2.push(i, cur[1]/ids.length, cur[2]/ids.length);
});
}

Related

Multidimensional array JS snippest

In below given JavaScript code I am unable achieve expected output. please help me to get resolve the given code.
Please check for the expected output.
In below given JavaScript code I am unable achieve expected output. please help me to get resolve the given code.
Please check for the expected output.
$(document).ready(function(){
var record = [];
var idarr = ['5','2','-','3','-'];
var jobidarr = [];
var userid = 32;
var newlogtimedata = ["2020/11/14 13:29:30","-","2020/10/10 13:33:49","-"];
var newlogtimedataupdate = [];
var logcnt = 1;
var j=0;
for(var i = 0; i < newlogtimedata.length; i++){
if(newlogtimedata[i] != "-"){
newlogtimedataupdate.push(newlogtimedata[i]);
}
}
for(var i = 0; i < idarr.length; i++){
if(idarr[i] == "-"){
logcnt++;
}
else{
//for(var j = 0; j < idarr.length; j++){
record[[j]] = new Array();
record[[j]].push(parseInt(idarr[i]));
record[[++j]]= new Array();
/* record[[j]].push(JSON.stringify(parseInt(userid)));
record[[j]].push("-");
record[[++j]] = new Array();
record[[j]].push(newlogtimedataupdate[logcnt-1]);
record[[j]].push("-"); */
j++;
//}
}
}
console.log("record:::", record);
});
/*
expected output will be
record:::
[ [5, 32, ['2020/11/14 13:29:30','-'],
[2, 32, ['2020/11/14 13:29:30','-'],
[3, 32, ['2020/10/10 13:33:49','-'] ]; */
I believe this your desired result, not sure what it's supposed to represent though:
var idarr = ['5', '2', '-', '3', '-'];
var userid = 32;
var newlogtimedata = [
"2020/11/14 13:29:30", "-",
"2020/10/10 13:33:49", "-"
];
const result = idarr.reduce((a, c, i) => {
if (c === '-') return a;
a.push([
parseInt(c, 10),
userid,
[
newlogtimedata[i] === '-' ? newlogtimedata[i - 1] : newlogtimedata[i],
'-'
]
]);
return a;
}, []);
console.log(result)
Try this:
for(var j = 0; j < idarr.length; j++){
record.push([
parseInt(idarr[i]),
userid,
[newlogtimedataupdate[logcnt - 1], '-']
]);
}
To access data inside multi-dimensional arrays, it looks like this myArray[2][1].
Example:
Here's a multi-dimensional array with some random values:
let myArray = [
['cake', 'cookie'],
['car', 'plane', 'train']
];
To access the elements inside myArray, you first select the index of one of the inner arrays. That means myArray[0] looks like: ['cake', 'cookie'], and now you can select the elements inside the inner array like so: myArray[0][1] (which is 'cookie').
You could use two indices for the arrays and pick an item as long as no sparator is coming.
let idarr = ['5', '2', '-', '3', '-'],
userid = 32,
newlogtimedata = ["2020/11/14 13:29:30", "-", "2020/10/10 13:33:49", "-"],
SEPARATOR = '-',
record = [],
i = 0,
j = 0;
while (i < idarr.length && j < newlogtimedata.length) {
record.push([idarr[i], userid, [newlogtimedata[j], '-']]);
if (idarr[i + 1] === SEPARATOR && newlogtimedata[j + 1] === SEPARATOR) {
i += 2;
j += 2;
continue;
}
if (idarr[i + 1] !== SEPARATOR) i++;
if (newlogtimedata[j + 1] !== SEPARATOR) j++;
}
console.log(record);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to clean , from a given string?

I have data like this.
var abc =",,,,,,,,,,,,,,,paul,2000,12sc21,logan,123,21sdf34,vfsarwe,456456,32fd23";
abc = abc.split(",");
let stub={};
var results=[];
var key=["name","value","acc"];
var i=0;
var j=0;
for( var i = 0 ; i <abc.length - 1;i++){
stub[key[j]=abc[i];
j++
if(j==3){
results.push(stub);
stub={};
j=0;
}
}
abc = results;
I would like to get those values arranges in form of array of object having those 3 keys:
output should be:
abc = [{"name": "paul", "value": "2000","acc":"12sc21"},{"name":"logan","value":"123","acc":"21sdf34"},{"name":"vfsarwe","value":"456456","acc":"32fd23"}];
but not able to get the desired output. this output only comes when string don't have ,,,,,, in starting. But the data i'm getting is sometimes having ,,,,, in stating.
You can use abc.replace(/(^[,\s]+)/g, '') to remove leading commas or whitespace from the String. Your for loop is also not running for long enough; it is looping until there is only one element left in the Array and then stopping.
Change
for(var i = 0 ; i < abc.length-1; i++)
To
for(var i = 0 ; i < abc.length; i++)
var abc =",,,,,,,,,,,,,,,paul,2000,12sc21,logan,123,21sdf34,vfsarwe,456456,32fd23";
abc = abc.replace(/(^[,\s]+)|([,\s]+$)/g, '').split(",");
let stub={};
var results=[];
var key=["name","value","acc"];
var i=0;
var j=0;
for(var i = 0 ; i < abc.length; i++){
stub[key[j]]=abc[i];
j++
if(j==3){
results.push(stub);
stub={};
j=0;
}
}
abc = results;
console.log(abc);
You can use .replace(/^\,+/, '') to remove all leading commas, then split by comma to get an array, then loop over this array using 3 as step and construct your results:
var abc = ",,,,,,,,,,,,,,,paul,2000,12sc21,logan,123,21sdf34,vfsarwe,456456,32fd23";
var arr = abc.replace(/^\,+/, '').split(",");
var results = [];
for (var i = 0; i < arr.length; i = i + 3) {
results.push({
"name": arr[i],
"value": arr[i + 1],
"acc": arr[i + 2]
});
}
Demo:
var abc = ",,,,,,,,,,,,,,,paul,2000,12sc21,logan,123,21sdf34,vfsarwe,456456,32fd23";
var arr = abc.replace(/^\,+/, '').split(",");
var results = [];
for (var i = 0; i < arr.length; i = i + 3) {
results.push({
"name": arr[i],
"value": arr[i + 1],
"acc": arr[i + 2]
});
}
console.log(results);
You are on the right track with splitting your data on ,. You can then split the data in to chunks of 3, and from there map each chunk to a dict.
var data = ",,,,,,,,,,,,,,,paul,2000,12sc21,logan,123,21sdf34,vfsarwe,456456,32fd23";
var split = data.split(",");
var chunked = [];
while (split.length) {
chunked.push(split.splice(0,3));
}
var res = chunked.map((i) => {
if (!i[0] || !i[1] || !i[2]) {
return null;
}
return {
name: i[0],
value: i[1],
acc: i[2]
};
}).filter((i) => i !== null);
console.log(res);
You can use:
abc.replace(/,+/g, ',').replace(/^,|,$/g, '').split(',');
The regEx replaces removes the data that you are not interested in before performing the split.
or
abc.split(',').filter(Boolean);
The filter(Boolean) will remove the items from the array that could be the equivalent of false once the array has been instantiated.
EDIT:
var abc =",,,,,,,,,,,,,,,paul,2,000,12sc21,logan,123,21sdf34,vfsarwe,456456,32fd23";
var array = abc.replace(/,+/g, ',').replace(/^,|,$/g, '').split(/,([0-9,]+),/);
array = array.filter(Boolean).reduce(function(acc, item) {
if (item.match(/^[0-9,]+$/)) {
acc.push(item);
} else {
acc = acc.concat(item.split(','));
}
return acc;
}, []);

Looping and storing different length of obj in javascript

I am trying to iterate in an array
[1,2,3,4,5,6]
And I want to store them in an object so that:
[
{1},
{1,2},
{1,2,3},
{2,3,4},
{3,4,5},
{4,5,6}
]
As you may notice, the first element to be pushed in the array is removed first if the limit of 3 was reached.
I'm doing this:
var given = [1,2,3,4,5,6];
var limit = 3;
var start = 1;
var result = [];
for (var i = 0; i < given.length; i++) {
var j = 0;
while(j <= start) {
j++;
if(start <= limit) {start++};
result.push(given[i]);
}
};
console.log(result);
Seems like my answer is super wrong, i'm still stuck at pushing it 1 by 1 then increase. So i haven't yet, think of replacing the oldest element.
EDIT:
Also I'm thinking of not shifting the array and put the new value to the end instead replace the value and maintain their indexes...
i mean
[
{1},
{1,2},
{1,2,3},
{4,2,3},
{4,5,3},
{4,5,6}
]
Try
var given = [1, 2, 3, 4, 5, 6];
var limit = 3;
var start = 1;
var result = [], rec = [];
for (var i = 0; i < given.length; i++) {
rec = rec.slice(0);
if(rec.length == limit){
rec.shift();
}
rec.push(given[i]);
result.push(rec)
}
console.log(JSON.stringify(result));
Demo: Fiddle
O/P
[[1],[1,2],[1,2,3],[2,3,4],[3,4,5]]
Update
var given = [1, 2, 3, 4, 5, 6];
var limit = 3;
var start = 1;
var result = [],
rec = [];
for (var i = 0; i < given.length; i++) {
rec = rec.slice(0);
rec[i % limit] = given[i]
result.push(rec)
}
console.log(JSON.stringify(result));
Demo: Fiddle
O/P
[[1],[1,2],[1,2,3],[4,2,3],[4,5,3],[4,5,6]]

JavaScript - Generating combinations from n arrays with m elements [duplicate]

This question already has answers here:
Cartesian product of multiple arrays in JavaScript
(35 answers)
Closed 1 year ago.
I'm having trouble coming up with code to generate combinations from n number of arrays with m number of elements in them, in JavaScript. I've seen similar questions about this for other languages, but the answers incorporate syntactic or library magic that I'm unsure how to translate.
Consider this data:
[[0,1], [0,1,2,3], [0,1,2]]
3 arrays, with a different number of elements in them. What I want to do is get all combinations by combining an item from each array.
For example:
0,0,0 // item 0 from array 0, item 0 from array 1, item 0 from array 2
0,0,1
0,0,2
0,1,0
0,1,1
0,1,2
0,2,0
0,2,1
0,2,2
And so on.
If the number of arrays were fixed, it would be easy to make a hard coded implementation. But the number of arrays may vary:
[[0,1], [0,1]]
[[0,1,3,4], [0,1], [0], [0,1]]
Any help would be much appreciated.
Here is a quite simple and short one using a recursive helper function:
function cartesian(...args) {
var r = [], max = args.length-1;
function helper(arr, i) {
for (var j=0, l=args[i].length; j<l; j++) {
var a = arr.slice(0); // clone arr
a.push(args[i][j]);
if (i==max)
r.push(a);
else
helper(a, i+1);
}
}
helper([], 0);
return r;
}
Usage:
cartesian([0,1], [0,1,2,3], [0,1,2]);
To make the function take an array of arrays, just change the signature to function cartesian(args) instead of using rest parameter syntax.
I suggest a simple recursive generator function:
// JS
function* cartesianIterator(head, ...tail) {
const remainder = tail.length ? cartesianIterator(...tail) : [[]];
for (let r of remainder) for (let h of head) yield [h, ...r];
}
// get values:
const cartesian = items => [...cartesianIterator(items)];
console.log(cartesian(input));
// TS
function* cartesianIterator<T>(items: T[][]): Generator<T[]> {
const remainder = items.length > 1 ? cartesianIterator(items.slice(1)) : [[]];
for (let r of remainder) for (let h of items.at(0)!) yield [h, ...r];
}
// get values:
const cartesian = <T>(items: T[][]) => [...cartesianIterator(items)];
console.log(cartesian(input));
You could take an iterative approach by building sub arrays.
var parts = [[0, 1], [0, 1, 2, 3], [0, 1, 2]],
result = parts.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));
console.log(result.map(a => a.join(', ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
After doing a little research I discovered a previous related question:
Finding All Combinations of JavaScript array values
I've adapted some of the code from there so that it returns an array of arrays containing all of the permutations:
function(arraysToCombine) {
var divisors = [];
for (var i = arraysToCombine.length - 1; i >= 0; i--) {
divisors[i] = divisors[i + 1] ? divisors[i + 1] * arraysToCombine[i + 1].length : 1;
}
function getPermutation(n, arraysToCombine) {
var result = [],
curArray;
for (var i = 0; i < arraysToCombine.length; i++) {
curArray = arraysToCombine[i];
result.push(curArray[Math.floor(n / divisors[i]) % curArray.length]);
}
return result;
}
var numPerms = arraysToCombine[0].length;
for(var i = 1; i < arraysToCombine.length; i++) {
numPerms *= arraysToCombine[i].length;
}
var combinations = [];
for(var i = 0; i < numPerms; i++) {
combinations.push(getPermutation(i, arraysToCombine));
}
return combinations;
}
I've put a working copy at http://jsfiddle.net/7EakX/ that takes the array you gave earlier ([[0,1], [0,1,2,3], [0,1,2]]) and outputs the result to the browser console.
const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
console.log(charSet.reduce((a,b)=>a.flatMap(x=>b.map(y=>x+y)),['']))
Just for fun, here's a more functional variant of the solution in my first answer:
function cartesian() {
var r = [], args = Array.from(arguments);
args.reduceRight(function(cont, factor, i) {
return function(arr) {
for (var j=0, l=factor.length; j<l; j++) {
var a = arr.slice(); // clone arr
a[i] = factor[j];
cont(a);
}
};
}, Array.prototype.push.bind(r))(new Array(args.length));
return r;
}
Alternative, for full speed we can dynamically compile our own loops:
function cartesian() {
return (cartesian.cache[arguments.length] || cartesian.compile(arguments.length)).apply(null, arguments);
}
cartesian.cache = [];
cartesian.compile = function compile(n) {
var args = [],
indent = "",
up = "",
down = "";
for (var i=0; i<n; i++) {
var arr = "$"+String.fromCharCode(97+i),
ind = String.fromCharCode(105+i);
args.push(arr);
up += indent+"for (var "+ind+"=0, l"+arr+"="+arr+".length; "+ind+"<l"+arr+"; "+ind+"++) {\n";
down = indent+"}\n"+down;
indent += " ";
up += indent+"arr["+i+"] = "+arr+"["+ind+"];\n";
}
var body = "var res=[],\n arr=[];\n"+up+indent+"res.push(arr.slice());\n"+down+"return res;";
return cartesian.cache[n] = new Function(args, body);
}
var f = function(arr){
if(typeof arr !== 'object'){
return false;
}
arr = arr.filter(function(elem){ return (elem !== null); }); // remove empty elements - make sure length is correct
var len = arr.length;
var nextPerm = function(){ // increase the counter(s)
var i = 0;
while(i < len)
{
arr[i].counter++;
if(arr[i].counter >= arr[i].length){
arr[i].counter = 0;
i++;
}else{
return false;
}
}
return true;
};
var getPerm = function(){ // get the current permutation
var perm_arr = [];
for(var i = 0; i < len; i++)
{
perm_arr.push(arr[i][arr[i].counter]);
}
return perm_arr;
};
var new_arr = [];
for(var i = 0; i < len; i++) // set up a counter property inside the arrays
{
arr[i].counter = 0;
}
while(true)
{
new_arr.push(getPerm()); // add current permutation to the new array
if(nextPerm() === true){ // get next permutation, if returns true, we got them all
break;
}
}
return new_arr;
};
Here's another way of doing it. I treat the indices of all of the arrays like a number whose digits are all different bases (like time and dates), using the length of the array as the radix.
So, using your first set of data, the first digit is base 2, the second is base 4, and the third is base 3. The counter starts 000, then goes 001, 002, then 010. The digits correspond to indices in the arrays, and since order is preserved, this is no problem.
I have a fiddle with it working here: http://jsfiddle.net/Rykus0/DS9Ea/1/
and here is the code:
// Arbitrary base x number class
var BaseX = function(initRadix){
this.radix = initRadix ? initRadix : 1;
this.value = 0;
this.increment = function(){
return( (this.value = (this.value + 1) % this.radix) === 0);
}
}
function combinations(input){
var output = [], // Array containing the resulting combinations
counters = [], // Array of counters corresponding to our input arrays
remainder = false, // Did adding one cause the previous digit to rollover?
temp; // Holds one combination to be pushed into the output array
// Initialize the counters
for( var i = input.length-1; i >= 0; i-- ){
counters.unshift(new BaseX(input[i].length));
}
// Get all possible combinations
// Loop through until the first counter rolls over
while( !remainder ){
temp = []; // Reset the temporary value collection array
remainder = true; // Always increment the last array counter
// Process each of the arrays
for( i = input.length-1; i >= 0; i-- ){
temp.unshift(input[i][counters[i].value]); // Add this array's value to the result
// If the counter to the right rolled over, increment this one.
if( remainder ){
remainder = counters[i].increment();
}
}
output.push(temp); // Collect the results.
}
return output;
}
// Input is an array of arrays
console.log(combinations([[0,1], [0,1,2,3], [0,1,2]]));
You can use a recursive function to get all combinations
const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
let loopOver = (arr, str = '', final = []) => {
if (arr.length > 1) {
arr[0].forEach(v => loopOver(arr.slice(1), str + v, final))
} else {
arr[0].forEach(v => final.push(str + v))
}
return final
}
console.log(loopOver(charSet))
This code can still be shorten using ternary but i prefer the first version for readability 😊
const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
let loopOver = (arr, str = '') => arr[0].map(v => arr.length > 1 ? loopOver(arr.slice(1), str + v) : str + v).flat()
console.log(loopOver(charSet))
Another implementation with ES6 recursive style
Array.prototype.cartesian = function(a,...as){
return a ? this.reduce((p,c) => (p.push(...a.cartesian(...as).map(e => as.length ? [c,...e] : [c,e])),p),[])
: this;
};
console.log(JSON.stringify([0,1].cartesian([0,1,2,3], [[0],[1],[2]])));

group array division

this code http://jsfiddle.net/minagabriel/5MQ77/
var flowShadeBigArray =[] ;
var x = [7, 411, 780]
var y = [286, 712, 1058]
for( var i = 0 ; i< x.length;i++){
for(var index = x[i]; index <= y[i] ; index++ ){
var temp = [] ;
temp.push(index) ;
flowShadeBigArray.push(temp);
}
}
console.log(JSON.stringify(flowShadeBigArray));
generate the following array
[[7],[8],[9],[10],[11],[12],[13],[14]................[1056],[1057],[1058]]
i want to create a three arrays inside flowShadeBigArray and have the [x[i] ... y[i] ]
grouped together:
example
[ [ [7]....[286] ] , [ [411]...[712] ] ,[ [780]...[1058] ] ]
NOTE i still need to keep each of these numbers as an array so i can use it an an index for something else
THANKS
Just move the temp initialization to the first loop, before the second, and the .push() to the first loop after the second (or before, doesn't matter).
var flowShadeBigArray = [];
var x = [7, 411, 780]
var y = [286, 712, 1058]
for (var i = 0; i < x.length; i++) {
var temp = [];
for (var index = x[i]; index <= y[i]; index++) {
temp.push(index);
}
flowShadeBigArray.push(temp);
}
http://jsfiddle.net/5MQ77/1/
If each individual number belongs in its own Array, then change this:
flowShadeBigArray.push(temp);
to this:
flowShadeBigArray.push([temp]);
-edited
function range(from, to) {
var arr = [];
while (from <= to) {
arr.push([i++]);
}
return arr;
}
var result = [];
for (var i=0; i<x.length; i++) {
result.push(range(x[i], y[i]));
}

Categories