Pass data to a function untill array length - javascript

So I have a function that takes multiple arrays as arguments but the data I have is already in an array (say mainArr). so mainArr is an array that contains multiple array items that I need to put them in the function arguments.
here's the code:
// NOTE: YOU DON'T NEED TO UNDERSTAND THIS FUNCTION
function getCombinations(...args) {
let r = [], max = args.length - 1;
function helper(arr, i) {
for (let j = 0; j < args[i].length; j++) {
let a = arr.slice(0); // clone arr
a.push(args[i][j].value);
if (i === max) {
r.push(a);
} else {
helper(a, i + 1);
}
}
}
helper([], 0);
return r;
}
I want something like this:
const mainArr = [
{
values: [
{ value: 1 },
{ value: 2 }
]
}, {
values: [
{ value: 2 },
{ value: 1 }
]
}
]
getCombinations(mainArr[0].values, mainArr[1].values)
actually, I want to get the combinations of arrays and the function I made to get the combination, takes multiple arrays as arguments. for example, if I want to get the combination of two arrays, it takes two arrays as two different arguments. but the data I have is inside another array so I just want to strip the arrays from that single array.

Make the parameter of function getCombinations an array.
function getCombinations(args) {
let r = [], max = args.length - 1;
function helper(arr, i) {
for (let j = 0; j < args[i].length; j++) {
let a = arr.slice(0); // clone arr
a.push(args[i][j].value);
if (i === max) {
r.push(a);
} else {
helper(a, i + 1);
}
}
}
helper([], 0);
return r;
}
const mainArr = [
{
values: [
{ value: 1 },
{ value: 2 }
]
}, {
values: [
{ value: 2 },
{ value: 1 }
]
}
]
const x = getCombinations([mainArr[0].values, mainArr[1].values]);
console.log(x);
const list = mainArr.map(node => node.values);
const y = getCombinations(list);
console.log(y);

Related

Find combination of nested JSON keys

I am having some trouble solving this issue without using nested for-loops. I would like to do it using recursion.
Given the following object:
{
"Color": {
"Black": [],
"White": []
},
"Effect": {
"30W": [],
"40W": [],
"60W": []
}
}
The code should compute each combination of Color and Effect and add a number in the list such that the following is produced:
{
"Color": {
"Black": [
1,
2,
3
],
"White": [
4,
5,
6
]
},
"Effect": {
"30W": [
1,
4
],
"40W": [
2,
5
],
"60W": [
3,
6
]
}
}
My attempt is as follows:
const func = (object, entries) => {
for (let prop in object) {
let counter = 0;
const objLength = Object.keys(object[prop]).length;
for (let key in object[prop]) {
console.log(key + counter)
for (let i = 0; i < entries.length / objLength; i++) {
object[prop][key].push(entries[counter]);
counter++;
}
}
}
return object;
}
However, this does not return the desired output. I think it is because of the inner-most for loop condition.
The best way to handle this is to create your JavaScript object and convert it to a string.
// creating your object with attributes. Objects in objects or whatever you
// need
var obj = new Object();
obj.name = "Dale";
obj.age = 30;
obj.married = true;
dataToAdd.forEach(function(item, index) {
item.married = false;
})
// Then convert it to a string using the following code
var jsonString= JSON.stringify(obj);
console.log(jsonString);
I solved the question by considering the space of each attribute key. Then it is just a matter of finding the cartesian, and adding values accordingly:
const cartesian =(...a) => a.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())));
function diy(jsonObj, counter) {
let permObj = []
let keys = Object.keys(jsonObj)
keys.forEach(key => {
permObj.push(Object.keys(jsonObj[key]))
});
permObj = cartesian(...permObj)
for(let i = 0; i < keys.length; i++) {
for(let j = 0; j < permObj.length; j++) {
jsonObj[keys[i]][permObj[j][i]].push(j + counter);
}
}
return jsonObj;
}

convert special array to object [duplicate]

This question already has answers here:
Create objects dynamically out of a dot notation like string
(6 answers)
Closed 1 year ago.
I am trying to convert the following array into an object:
var arr = [
'car.name',
'car.age',
'car.event.id',
'zz.yy.dd.aa',
'aa.yy.zz.dd.kk'
];
So it will look like this:
var targetObject = {
car: {
name: '',
age: '',
event: {
id: ''
}
}
,
zz: {
yy: {
dd: {
aa: ''
}
}
},
aa: {
yy: {
zz: {
dd: {
kk: '',
}
}
}
}
}
This is my code:
targetObject = {}
function arrayToObject(arr){
//iterate through array and split into items
for (var i = 0; i < arr.length; ++i){
var item = arr[i].split(".");
//iterate through item that has just been splitted
for (var u = 0; u < item.length; ++u){
//if item is not in targetobject create new object
if(!(item[0] in targetObject)){
targetObject[item[0]] = {}
} else {
//else go into the object and add the item/property to the existing object
targetObject[item[0]][item[u]] = {}
}
}
}
console.log(targetObject);
}
arrayToObject(arr);
It outputs only in second level and i can't figure out to do it with the several levels. I know the code is oldschool, so I would also really like to know how this can be done easier.
You could use forEach to loop over array and then split with reduce to build nested object.
var arr = [
'car.name',
'car.age',
'car.event.id',
'zz.yy.dd.aa',
'aa.yy.zz.dd.kk'
];
const result = {}
arr.forEach(str => {
str.split('.').reduce((r, e, i, a) => {
return r[e] = (r[e] || (a[i + 1] ? {} : ''))
}, result)
})
console.log(result)
Or with your approach with for loops you just need to keep some reference and update the current nested object, so you could do it like this.
var arr = [
'car.name',
'car.age',
'car.event.id',
'zz.yy.dd.aa',
'aa.yy.zz.dd.kk'
];
const targetObject = {}
let ref = targetObject;
function arrayToObject(arr) {
//iterate through array and split into items
for (var i = 0; i < arr.length; ++i) {
var item = arr[i].split(".");
//iterate through item that has just been splitted
for (var u = 0; u < item.length; ++u) {
const last = u == item.length - 1
const str = item[u]
if (!ref[str]) {
ref[str] = (last ? '' : {})
}
ref = ref[str]
if (last) {
ref = targetObject;
}
}
}
}
arrayToObject(arr);
console.log(targetObject)

Merge 2 arrays keeping inner elements array values

I'm trying to merge 2 objects which contains arrays in one of their elements. I don't achieve the disered result when using spread syntax and the first object array is being replaced by the second one. The objects are like the following:
const objectA1 = {
keyA1:'valueA1',
keyArr:[{
arrKeyA01:'arrValueA01',
arrKeyA02:'arrValueA02',
},
{
arrKeyA11:'arrValueA11',
arrKeyA12:'arrValueA12',
}
]
}
const objectB1 = {
keyB1:'valueB1',
keyArr:[{
arrKeyB01:'arrValueB01',
arrKeyB02:'arrValueB02',
},
{
arrKeyB11:'arrValueB11',
arrKeyB12:'arrValueB12',
}
]
}
And I want to get:
const objectRes = {
keyA1:'valueA1',
keyB1:'valueB1',
keyArr:[{
arrKeyA01:'arrValueA01',
arrKeyA02:'arrValueA02',
arrKeyB01:'arrValueB01',
arrKeyB02:'arrValueB02',
},
{
arrKeyA11:'arrValueA11',
arrKeyA12:'arrValueA12',
arrKeyB11:'arrValueB11',
arrKeyB12:'arrValueB12',
}
]
}
What I'm using is
{...objectA1 ,...objectB1}
But as said, the keyArr doesn't keep the objectA1 elements.
How I can merge both objects and keep the array data using spread syntax?
Thanks for any comment/help :)
Create an object and place the first 2 values from A1 and B2 object. Customize the array separately by using reduce
const objectA1 = {
keyA1: 'valueA1',
keyArr: [{
arrKeyA01: 'arrValueA01',
arrKeyA02: 'arrValueA02',
},
{
arrKeyA11: 'arrValueA11',
arrKeyA12: 'arrValueA12',
}
]
}
const objectB1 = {
keyB1: 'valueB1',
keyArr: [{
arrKeyB01: 'arrValueB01',
arrKeyB02: 'arrValueB02',
},
{
arrKeyB11: 'arrValueB11',
arrKeyB12: 'arrValueB12',
}
]
}
const arr = objectA1.keyArr.reduce((acc, x) => {
const res1 = objectB1.keyArr.reduce((acc2, y) => ({...x,...y}), {})
return acc = [...acc, res1];
}, [])
const result = {
keyA1: objectA1.keyA1,
keyB1: objectB1.keyB1,
keyArr: arr
}
console.log(result)
I wanted to share my attemp solving this problem, I take the array and merge it in one using loops:
const objectA1 = {
keyA1:'valueA1',
keyArr:[{
arrKeyA01:'arrValueA01',
arrKeyA02:'arrValueA02',
},
{
arrKeyA11:'arrValueA11',
arrKeyA12:'arrValueA12',
}
]
}
const objectB1 = {
keyB1:'valueB1',
keyArr:[{
arrKeyB01:'arrValueB01',
arrKeyB02:'arrValueB02',
},
{
arrKeyB11:'arrValueB11',
arrKeyB12:'arrValueB12',
}
]
}
objects = [objectA1, objectB1];
let i = 0;
new_array = {};
for(i; i < objects.length; i++){
object = objects[i];
keys = Object.keys(object);
for(j = 0; j < keys.length; j++){
//if property already exists, example keyArr
this_key = keys[j];
console.log(this_key);
if(new_array[this_key] != undefined){
//loop through that property in the object
object[this_key].forEach((object_value, index) => {
//add all properties that previous object did not have
Object.assign(new_array[this_key][index], object_value);
});
}else{
//initialize that value with the first element array
new_array[this_key] = object[this_key];
}
}
}
console.log(objects);
console.log(new_array);

JavaScript - find unique values in array of objects, with count and create a new array of objects

I have an array of objects as below:
var arr =[
{
price:20,
rule:a
},
{
price:10,
rule:b
},
{
price:5,
rule:a
},
{
price:50,
rule:b
},
{
price:70,
rule:b
}
]
I want to extract an array of objects out of this as below:
var filteredArr = [
{
rule:a,
countOfRule:2,
minPriceForThisRule:5
},
{
rule:b,
countOfRule:3,
minPriceForThisRule:10
}
]
This means:
1) I want to create new array with no. of objects as unique no. of rules in first array "arr"
2) Need to count the unique rule repetition and add as property in new array objects - given as "countOfRule"
3) Find the minimum price for in a category of unique rule - given as "minPriceForThisRule"
I have read similar answers on SO and was able to get first 2 conditions only, and that too were not in the format as i need.
What I tried, referring to links on SO:
var ff = {},e;
for (var i = 0,l=arr.length; i < l; i++) {
e = arr[i];
ff[e.rule] = (ff[e.rule] || 0) + 1;
}
But this gives only a single object as
{
a : 2,
b: 3
}
You can do this with forEach and thisArg optional parameter.
var arr = [{"price":20,"rule":"a"},{"price":10,"rule":"b"},{"price":5,"rule":"a"},{"price":50,"rule":"b"},{"price":70,"rule":"b"}],
r = [];
arr.forEach(function(e) {
if(!this[e.rule]) {
this[e.rule] = {rule: e.rule, countOfRule: 0, minPriceForThisRule: e.price}
r.push(this[e.rule]);
}
this[e.rule].countOfRule++;
if(this[e.rule].minPriceForThisRule > e.price) this[e.rule].minPriceForThisRule = e.price;
}, {});
console.log(r)
I would use reduce. Something like:
var reduced = arr.reduce(function(memo, obj){
var rule = memo[obj.rule];
rule.countOfRule++;
if(!rule.minPriceForThisRule){
rule.minPriceForThisRule = obj.price;
} else{
if(obj.price < rule.minPriceForThisRule){
rule.minPriceForThisRule = obj.price;
}
}
return memo;
}, map);
where the initial map looks like:
var map = {
1: {
rule: 1,
countOfRule: 0,
minPriceForThisRule: null
},
2: {
rule: 2,
countOfRule: 0,
minPriceForThisRule: null
}
}
Of course you could dynamically create the map if needed.
https://plnkr.co/edit/wLw3tEx2SMXmYE7yOEHg?p=preview
This is how i would do this job,
var arr =[
{
price:20,
rule:"a"
},
{
price:10,
rule:"b"
},
{
price:5,
rule:"a"
},
{
price:50,
rule:"b"
},
{
price:70,
rule:"b"
}
],
reduced = arr.reduce((p,c) => { var fo = p.find(f => f.rule == c.rule);
fo ? (fo.countOfRule++,
fo.minPriceForThisRule > c.price && (fo.minPriceForThisRule = c.price))
: p.push({rule:c.rule, countOfRule:1, minPriceForThisRule: c.price});
return p;
},[]);
console.log(reduced);
Arrows might not work at IE or Safari. If that would be a problem please replace them with their conventional counterparts.

Add or remove element(s) to array

I have an existing array of objects :
existingArray = [
{object1: 'object1'},
{object2: 'object2'}
{object3: 'object3'},
]
I receive a new one :
newArray = [
{object2: 'object2'},
{object3: 'object3'},
{object4: 'object4'}
]
I want only to modify the existing one to get the new one as the result (push+splice)
Here is what I have for now (is there a better way ?)
for (var i = 0; i < newArray.length; i++) {
// loop first to push new elements
var responseToTxt = JSON.stringify(newArray[i]);
var newStatement = false;
for(var j = 0; j < existingArray.length; j++){
var statementToTxt = JSON.stringify(existingArray[j]);
if(statementToTxt === responseToTxt && !newStatement){
newStatement = true;
}
}
if(!newStatement){
statements.push(response[i]);
}
}
var statementsToSplice = [];
for (var i = 0; i < existingArray.length; i++) {
// then loop a second time to split elements not anymore on the new array
var statementToTxt = JSON.stringify(existingArray[i]);
var elementPresent = false;
var element = false;
for(var j = 0; j < newArray.length; j++){
var responseToTxt = JSON.stringify(newArray[j]);
if(responseToTxt === statementToTxt && !elementPresent){
elementPresent = true;
} else {
element = i;
}
}
if(!elementPresent){
statementsToSplice.push(element);
}
}
Then I needed to split multiple times in the array :
existingArray = statementsToSplice.reduceRight(function (arr, it) {
arr.splice(it, 1);
return arr;
}, existingArray.sort(function (a, b) { return b - a }));
Here is the example :
https://jsfiddle.net/docmz22b/
So the final output should always be the new array, but only by push or splice the old one.
In this case, the final outpout will be
existingArray = [
{object2: 'object2'},
{object3: 'object3'}
{object4: 'object4'},
]
The new array could contains multiple new elements and/or deleted elements that is currently in the existingArray
Use shift() and push()
existingArray.shift(); //Removes the first element of the array
existingArray.push({'object4' : 'object4'});
Fiddle
I'm almost 100% sure that there is a better way to do it, but at least this works, feel free to comment any suggestions / optimizations.
existingArray = [
{object1: 'object1'},
{object2: 'object2'},
{object3: 'object3'}
];
newArray = [
{object2: 'object2'},
{object3: 'object3'},
{object4: 'object4'}
];
// Loop all the old values, if is not in the new array, remove it
existingArray.forEach(function(item) {
if(!inArray(item, newArray)) {
var idx = indexOfObjectInArray(item, existingArray);
existingArray.splice(idx, 1);
}
});
// Loop all the new values, if is not in the new array, push it
newArray.forEach(function(item) {
if (!inArray(item, existingArray)) {
existingArray.push(item);
}
});
// Auxiliar functions
function inArray(initialValue, array) {
testValue = JSON.stringify(initialValue);
return array.some(function(item) {
return testValue == JSON.stringify(item);
});
}
function indexOfObjectInArray(initialValue, array) {
var result = -1;
testValue = JSON.stringify(initialValue);
array.forEach(function(item, idx) {
if (testValue == JSON.stringify(item)) {
result = idx;
};
});
return result;
}
Maybe this helps. It features Array.prototype.forEach and Array.prototype.some.
Splice unwanted items
Look if object with same property exist
If yes, then assign new object
Else push the object
var existingArray = [
{ object1: 'object1' },
{ object2: 'object2' },
{ object3: 'object3' },
],
newArray = [
{ object2: 'object22' },
{ object3: 'object33' },
{ object4: 'object44' }
];
function update(base, change) {
var changeKeys = change.map(function (a) { return Object.keys(a)[0]; }),
i = 0;
while (i < base.length) {
if (!~changeKeys.indexOf(Object.keys(base[i])[0])) {
base.splice(i, 1);
continue;
}
i++;
}
change.forEach(function (a) {
var aKey = Object.keys(a)[0];
!base.some(function (b, i, bb) {
if (aKey === Object.keys(b)[0]) {
bb[i] = a; // if that does not work, use bb.splice(i, 1, a);
return true;
}
}) && base.push(a);
});
}
update(existingArray, newArray);
document.write('<pre>' + JSON.stringify(existingArray, 0, 4) + '</pre>');

Categories

Resources