How to compare two array and push data based on result Angular - javascript

I have add my all code below, but important function is patchDataCollection() where i have added push logic for forms.
I want to compare values of both arrayOne and arrayTwo based on below condition and if it matches than it will pass data along with form otherwise it will create an empty form.
Expected output
I have created patchDataCollection() function where i am creating forms based on above condition, but in my case it is patching data to all generated forms
, i want only patch thosa object which are avlbl in arrayTww.
Below condition i wanted to check in arrayOne and arrayTwo.
if arrayOne processTypeId is equal to arrayTwo of makeProcessTypeId And
arrayOne makeLineName is equal to arrayTwo of makeLineName And
arrayOne processTechType is equal to arrayTwo of processTechType than
If all above conditions are met than only dataOne variable will pass along with form.
this.itemTypes().push(this.createContinuousForm(item, dataOne));
else it will create an empty form only without pushing dataOne in form.
this.itemTypes().push(this.createContinuousForm(item));
Const arrayOne = [
{
"makeLineName": "Red",
types : [
{
"processTypeId": 101,
"processTechType": "Batch"
},
{
"processTypeId": 102,
"processTechType": "Batch"
}
]
},
{
"makeLineName": "Blue",
types : [
{
"processTypeId": 103,
"processTechType": "Continuous"
},
{
"processTypeId": 104,
"processTechType": "Batch"
}
]
}
];
Const arrayTwo =
[
{
"makeProcessTypeId": 101,
"makeLineName": "Red",
"processTechType": "Batch",
"avgBct": 23,
"bestBct": 23
},
{
"makeProcessTypeId": 102,
"makeLineName": "Blue",
"processTechType": "Batch",
"avgBct": 45,
"bestBct": 45
},
{
"makeProcessTypeId": 103,
"makeLineName": "Blue",
"processTechType": "Continuous",
"designProcessCapacity": 250,
"minRunLength": 250
}
];
getMakeLineData() {
for (const line of arrayOne) {
const list = line.types;
for (const item of list) {
if (item.processTechType === 'Continuous') {
this.patchDataCollection(item);
} else if (item.processTechType === 'Batch' || item.processTechType === 'Batch-Crunch') {
this.patchDataCollection(item);
}
}
}
}
patchDataCollection(arrayOne) {
if (arrayTwo) {
for (const dataOne of arrayTwo) {
if (arrayOne.makeLineName == dataOne.makeLineName) {
if (arrayOne.processTechType === 'Continuous') {
this.itemTypes().push(this.createContinuousForm(item, dataOne));
}
if (dataOne.processTechType === 'Batch' || dataOne.processTechType === 'Batch-Crunch') {
this.itemTypes().push(this.createBatchForm(item, dataOne));
}
}
}
}
}
createContinuousForm(type, data) {
return this.fb.group({
makeLineName: [type.makeLineName],
processTechType: [type.processTechType],
makeProcessTypeId: [type.processTypeId],
designProcessCapacity: [data.designProcessCapacity ? data.designProcessCapacity : '', [Validators.required]],
minRunLength: [data.minRunLength ? data.minRunLength : '']
});
}
createBatchForm(type, data) {
return this.fb.group({
makeLineName: [type.makeLineName],
processTechType: [type.processTechType],
makeProcessTypeId: [type.processTypeId],
avgBct: [data.avgBct ? data.avgBct : '', [Validators.required]],
bestBct: [data.bestBct ? data.bestBct : '', [Validators.required]]
});
}
itemTypes(): FormArray {
return this.dataCollectionForm.get("items") as FormArray;
}

While I think there are better ways to store the data compared to what the API returns to you, it is certainly possible to compare the two arrays and only use the values that exist in both arrays, given your conditions.
The surrounding object with makeLineName and types in your arrayOne do not contain any valuable information (any information that is not within the types array anyway). You can start here with:
arrayOne.flatMap(i => i.types)
From my perspective the createContinuousForm and createBatchForm functions don't need two parameters. It should be enough if you pass the item from arrayTwo as the only values from arrayOne used in your functions are the one that must match the ones from arrayTwo.
I could see something in this direction working:
const arrayOne = [{
makeLineName: 'Red',
types: [{
processTypeId: '102',
processTechType: 'Batch',
makeLineName: 'Red',
}, ],
},
{
makeLineName: 'Blue',
types: [{
processTypeId: '103',
processTechType: 'Continuous',
makeLineName: 'Blue',
}, ],
},
];
const arrayTwo = [{
makeProcessTypeId: 101,
makeLineName: 'Red',
processTechType: 'Batch',
avgBct: 23,
bestBct: 23,
},
{
makeProcessTypeId: 102,
makeLineName: 'Blue',
processTechType: 'Batch',
avgBct: 45,
bestBct: 45,
},
{
makeProcessTypeId: 103,
makeLineName: 'Blue',
processTechType: 'Continuous',
designProcessCapacity: 250,
minRunLength: 250,
},
];
const simplifiedArrayOne = arrayOne.flatMap(i => i.types);
function createContinuousForm(item) {
console.log({
// if you put this into [], then your makeLineName is an array with one value
makeLineName: item.makeLineName,
processTechType: item.processTechType,
makeProcessTypeId: item.makeProcessTypeId,
designProcessCapacity: [
item.designProcessCapacity ? item.designProcessCapacity : ''
],
});
}
function createBatchForm(item) {
console.log({
makeLineName: item.makeLineName,
processTechType: item.processTechType,
makeProcessTypeId: item.makeProcessTypeId,
avgBct: item.avgBct ? item.avgBct : '',
bestBct: item.bestBct ? item.bestBct : '',
});
}
arrayTwo.filter(entry => {
// .toString() is necessary because your types of processTypeId (string) and makeProcessTypeId (number) are different
const index = simplifiedArrayOne.findIndex(e => e.processTypeId === entry.makeProcessTypeId.toString())
return index > -1 && entry.makeLineName === simplifiedArrayOne[index].makeLineName
}).forEach(item => item.processTechType === 'Continuous' ? this.createContinuousForm(item) : this.createBatchForm(item));
Please take note of the comments within the code. Also, as you're using TypeScript you could use an enum for the processTechType and possibly another one for the makeLineName as well

Related

Generate array into new array

Hi guys i got a complicated case for me
I have 4 array like this
[
{
"Id":1111111,
"OptionName":"Color",
"VariantName":"White"
},
{
"Id":2222222,
"optionName":"Size",
"VariantName":"XL"
},
{
"Id":3333333,
"OptionName":"Color",
"VariantName":"GREEN"
},
{
"Id":4444444,
"optionName":"Size",
"VariantName":"L"
}
]
So i want to merge the ID like
1 on 1, 1 on 2,2 on 1, 2 on 2
The result should be like this, but depend by variant name, so colours merge to size
[
{
"Id":1111111_2222222
...
},
{
"Id":1111111_4444444,
...
},
{
"Id":3333333_2222222,
...
},
{
"Id":3333333_4444444,
...
}
]
I already found how to group them by option Name, but how to merge it?
this is the code how i group them
const filteredVariantCats = variantCats
.map((a) => a.optionName)
.filter(onlyUnique)
.map((optionName) => {
let array = []
return variantCats
.filter((a) => a.optionName === optionName)
.map((a, idx) => {
array.push(a)
return a
})
})
UPDATE RESULT THAT I WANT TO RETURN IS THIS
{
id: null,
combinationStr: a.ID+"_"+b.ID,
name: a.variantName+' ,'+ b.variantName,
hex: '#000',
stock: 0,
price: 0,
priceDiscountType: OPTION.DISCOUNT_TYPE.NONE,
priceDiscount: 0,
weight: 10,
code: '',
attributeCode: 'a',
active: true,
productId: product.id from state,
}
Assume the syntax error and mis-matched cases are just error you make while writing the example and not actual mistakes in your actual code. If I understand correctly, you want to split the array into two groups, colors and sizes. Then generate all combinations between the two. Here is an example of how to do so. Since you mark ... in your expected output, I don't know what you actually expect so can only provide the Id field.
const arr = [
{
Id: 1111111,
OptionName: "Color",
VariantName: "White"
},
{
Id: 2222222,
OptionName: "Size",
VariantName: "XL",
},
{
Id: 3333333,
OptionName: "Color",
VariantName: "GREEN"
},
{
Id: 4444444,
OptionName: "Size",
VariantName: "L",
}
];
const colors = arr.filter(it => it.OptionName == "Color");
const sizes = arr.filter(it => it.OptionName == "Size");
let results = [];
for(let color of colors)
{
for(let size of sizes)
{
results.push({Id: `${color.Id}_${size.Id}`});
}
}
console.log(results);

How to push the first value of a list of arrays to object?

I have a nested array and want to push the first item from one of the arrays to state,
the Parent Array like this
"options": [
{
"id": 76,
"label_en": "Disk Storage",
"type": "text",
"product_id": 20,
"values": [
{
"id": 133,
"name_en": "32 GigByte",
"display_value": null,
"randam_key": "8596598ED", // this the target value I want to save
"option_id": 76
},
{
"id": 134,
"name_en": "16 GigByte",
"display_value": null,
"randam_key": "895454HG",
"option_id": 76
}
]
},
{
.....
}
]
every object from the "options - Parent" Array has a values array,
and every object of the values array has a randam_key
I want to save the first random key value from every object of the values array,
at the same time, i have a function that's store all values into a state to be like
//result
bodyQuery = {
"product_id": 20,
"values": {
"randam_key1": "895454HG",
"randam_key2": "FFJFOF568",
"randam_key3": "FDVHFDVD566"
}
}
const getUpdatedPrice = (randam_key: string, handleKey: string) => {
setBodyQuery((prevState) => ({
...prevState,
values: {
...prevState.values,
[handleKey]: randam_key,
},
}));
};
So what I tried is to get the keys 'Check the Live Code at the bottom', but i don't know how can I call getUpdatedPrice() to save the data as expected when the screen mounted.
the second case I have that saves the random keys after iterated the arrays and when I press to any item i call the getUpdatedPrice()
and this works very well but i need to do this behavior when screen mounted useEffect()!
#Second Case - Work as expected
{options.map((option) => {
....
{option.values.map((value: valueOptionProp, index) => {
// button
onPress={()=> getUpdatedPrice(
value.randam_key,
'randam_key' + (options.indexOf(option) + 1),
);
}
})}
})}
live code
{/* let optionsArr=[]
options.map((option) => {
optionsArr.push(option.values);
}
*/}
// the result of the above code is
optionsArr = [
[
{
display_value: null,
id: 133,
name_en: '32 GigByte',
option_id: 76,
randam_key: '8596598ED',
},
{
display_value: null,
id: 134,
name_en: '16 GigByte',
option_id: 76,
randam_key: '895454HG',
},
],
[
{
display_value: '#FFF',
id: 135,
name_en: 'Ù‹White',
option_id: 77,
randam_key: 'FGFFDCF54',
},
{
display_value: '#85FD',
id: 136,
name_en: 'Golden',
option_id: 77,
randam_key: 'FFJFOF568',
},
],
[
{
display_value: 'Url Image Here',
id: 137,
name_en: 'image 1',
option_id: 78,
randam_key: 'HGHVDF84585',
},
{
display_value: 'Url Image Here',
id: 138,
name_en: 'Image 2',
option_id: 78,
randam_key: 'FDVHFDVD566',
},
],
];
let first_randomKey = optionsArr.map(val=>val[0].randam_key);
console.log(first_randomKey);
#Edit
I try it like this and it works well!
If there any other solutions please let me know!
useEffect(() => {
let optionsArr: any[] = [];
item.options.map((option) => {
optionsArr.push(option.values);
});
let first_randomKey = optionsArr.map((val) => val[0].randam_key);
let keys = first_randomKey.map((_itemKeys) => {
getUpdatedPrice(
_itemKeys,
'randam_key' + (first_randomKey.indexOf(_itemKeys) + 1),
);
});
Promise.all(keys).then(() => {
isUpdated.current = true;
});
}, [item.options]);
useEffect(() => {
if (isUpdated.current) {
console.log('bodyQuery', bodyQuery);
}
}, [bodyQuery]);
There are a number of inconsistencies and inefficiencies in your final code, mostly around your use of Array.prototype.map().
Array.prototype.map() returns a new array, so declaring optionsArr and then using map() to push to it is redundant. You use it correctly in the next line however, when you assign first_randomKey by calling map() on the aforementioned optionsArr.
In your final map() call you are manually finding the index of the current iterated _itemsKeys but this is unnecessary as map() provides this for you as the second parameter of the callback. Again, elsewhere in your question you pass the index, but even then you aren't using it but manually finding the index.
The main inefficiency is that you using three map() calls for what could be achieved with one, here using destructuring assignment to access desired property, and leveraging the implicitly passed index parameter provided by map().
const keys = item.options.map(({ values: [{ randam_key }] }, index) =>
getUpdatedPrice(randam_key, 'randam_key' + (index + 1)));
or without destructuring
const keys = item.options.map((option, index) => {
const randam_key = option.values[0].randam_key;
return getUpdatedPrice(randam_key, 'randam_key' + (index + 1));
});
const item = { "options": [{ id: 1, values: [{ id: 133, randam_key: "8596598ED" }, { id: 134, randam_key: "895454HG", }] }, { id: 1, values: [{ id: 135, randam_key: 'FGFFDCF54', }, { id: 136, randam_key: 'FFJFOF568', },] }, { id: 1, values: [{ id: 137, randam_key: 'HGHVDF84585', }, { id: 138, randam_key: 'FDVHFDVD566', },] }] }
const getUpdatedPrice = async (key, indexedKey) => {
return [key, indexedKey]
}
const keys = item.options.map(({ values: [{ randam_key }] }, index) =>
getUpdatedPrice(randam_key, 'randam_key' + (index + 1)));
Promise.all(keys).then((result) => {
console.log(result)
});
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to iterate through a map in React JS

I have some data samples stored in a variable data_ as below.
[{'Age': 39, 'count': 5}, {'Age': 24, 'count': 5}]
So I have this javascript list as below:
barChartData(data) {
const datum = [
{
values: [
{
label: "A",
value: -29.765957771107,
color: "#3ebfea",
},
],
},
];
return datum;
}
// and use it
barChartData(data_) // passing the data sample to the function
And now what I want to do is, change the keys in the datum inside function with the data_ I pass.
so it will look like this:
barChartData(data) {
const datum = [
{
values: [
{
label: "Age",
value: <Age-received-from-data-parameter>,
color: "#3ebfea",
},
],
},
];
return datum;
}
How can I iterate/map the data inside the barChartData function and assign the value
I tried but I it is not working and I am pretty sure something is missing.
Can someone help me do this?
This is I what I tried
barChartData(data) {
const datum = [
{
// key: "Cumulative Return",
values: [
data.map((emp, index) =>
{ // below gives syntax errors
label: "Age",
value: emp.Age,
color: "#3ebfea",
}
)
],
},
];
return datum;
}
First, map function already returns an array, and it seems there's no need to wrap it into [] once more. Second, when arrow function returns an object, it should be wrapped into () to avoid confusing the parser. So here's one way your function might look like:
const source = [{
'Age': 39,
'count': 5
}, {
'Age': 24,
'count': 5
}];
// ----------------
function barChartData(data) {
const datum = [{
// key: "Cumulative Return",
values: data.map(emp => ({ // note `(` wrapper
label: "Age",
value: emp.Age,
color: "#3ebfea",
}))
}];
return datum;
}
console.log(barChartData(source));

how to assign object in object

how to assign the object in object and filter the value which pass and fail;
the input is:
[
{
name: 'John',
score: 90,
time: 'evening'
},
{
name: 'Doni',
score: 68,
time: 'morning'
},
{
name: 'Jiu',
score: 50,
time: 'evening'
},
{
name: 'Shin',
score: 92,
time: 'morning'
},
];
and i want the output like this :
{
"evening": {
"pass": [
{
"name": "John",
"score": 90
}
],
"fail": [
{
"name": "jiu",
"score": 50
}
]
},
"morning": {
"pass": [
{
"name": "Shin",
"score": 92
}
],
"fail": [
{
"name": "Doni",
"score": 68
}
]
}
}
do we need to use Object.assign for this ? and how many loop we use for this ??
i do love to know how to add another string in the object beside that ouput,
thanks
There's a lot of ways to do this. The simplest is probably to make a base object that represent your empty results. Then loop over the students and fill the arrays:
let students = [{name: 'John',score: 90,time: 'evening'},{name: 'Doni',score: 68,time: 'morning'},{name: 'Jiu',score: 50,time: 'evening'},{name: 'Shin',score: 92,time: 'morning'},];
// Empty case
let base = {
"evening": {"pass": [], "fail": []},
"morning": {"pass": [], "fail": []}
}
const PASSING = 70
students.forEach(({name, score, time}) => {
let key = score >= PASSING ? 'pass' : 'fail'
base[time][key].push({name, score})
})
console.log(base)
This makes is easy to have empty arrays, which is probably what you want if there are no students in a particular category.
EDIT based on comment:
To support arbitrary times, you can just create the times on the object as you find them. reduce() is good for this, but you could also use a regular loop. For example with an added afternoon time:
let students = [{name: 'Mark',score: 95,time: 'afternoon'}, {name: 'John',score: 90,time: 'evening'},{name: 'Doni',score: 68,time: 'morning'},{name: 'Jiu',score: 50,time: 'evening'},{name: 'Shin',score: 92,time: 'morning'},];
const PASSING = 70
let result = students.reduce((obj, {name, score, time}) => {
if (!obj[time]) obj[time] = {'pass': [], 'fail': [] }
let key = score >= PASSING ? 'pass' : 'fail'
obj[time][key].push({name, score})
return obj
}, {})
console.log(result)
You can do something like this:
const data = [{ name: 'John', score: 90, time: 'evening' }, { name: 'Doni', score: 68, time: 'morning' }, { name: 'Jiu', score: 50, time: 'evening' }, { name: 'Shin', score: 92, time: 'morning' }, ];
const grp = (d, p) => d.reduce((r,c) => (r[c[p]] = [...r[c[p]] || [], c], r), {})
const grpV = (d, rng) => d.reduce((r,{name, score}) => {
let key = score > rng ? 'pass' : 'fail'
r[key] = [...r[key] || [], {name, score}]
return r
}, {})
const r = Object.entries(grp(data, 'time')).map(([k,v]) => ({[k]: grpV(v, 75)}))
console.log(r)
The idea is the group 2 times one on the time and 2nd on the score.
grp: function to group by a property (in this case 'time') which returns an object with 2 properties: evening and morning each of which is an array containing the classes.
grpV: function to group by value (in this case 75) which returns an object with 2 properties: pass and fail each of which is an array containing the classes.
On the end once we have those tools we are saying ... give me the entries of the grouped by time object and for each of the groups ... group by score.
Here how something like this could look like if we ware using lodash:
const data = [{ name: 'John', score: 90, time: 'evening' }, { name: 'Doni', score: 68, time: 'morning' }, { name: 'Jiu', score: 50, time: 'evening' }, { name: 'Shin', score: 92, time: 'morning' }, ];
const partition = (x, p) => _(x)
.partition(y => y.score > p)
.map((x,i) => ({ [i==0 ? 'pass': 'fail']: _.omit(x[0], 'time')}))
.value()
const r = _(data)
.groupBy('time')
.mapValues(x => partition(x, 75))
.value()
console.log(r)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Adding it as an example since it does help with readability of what the ES6 example is doing to some extend.
I'm sure there are more elegant ways to do this. But this one is probably one of the simplest beginner-friendly ways you can go about this.
I loop through the input array, check the existence of the .time values as keys on the output object and create the pass and fail keys. Then evaluate the .score against the passingScore and push the necessary data to it.
Should be pretty easy to understand once you see and try the code below:
const data = [
{name: 'John',score: 90, time: 'evening'},
{name: 'Doni',score: 68, time: 'morning'},
{name: 'Jiu',score: 50, time: 'evening'},
{name: 'Shin',score: 92, time: 'morning'},
{name: 'Fubar',score: 75, time: 'noon'},
];
function formatData(data){
const passingScore = 75;
const output = {};
data.forEach(function(item){
if(!output[item.time]) output[item.time] = {pass: [], fail: []};
const stud = { name: item.name, score: item.score };
if(item.score >= passingScore) output[item.time]['pass'].push(stud)
else output[item.time]['fail'].push(stud)
});
return output;
}
console.log(formatData(data));

How can I Club/Combine multiple objects with same name as single object (Nesting)

I have a data of students and their marks in various subjects as an array of objects. I need to club the data as a single object when the name of the two objects are same so that I will have only one record for each student. An example of the sample data:
{
data: [{
"name: xxx,
"createdDate:10/01/2018,
subj1: 20,
subj2: 40
},
{
"name: xxx,
"createdDate:10/11/2017,
subj1: 40,
subj2: 70
},
{
"name: yyy,
"createdDate:10/01/2018,
subj1: 20,
subj2: 40
}]
}
and I need to convert it something like this:
{
data: [
{
name: xxx,
subj1: [20, 40],
subj2: [70, 40]
},
{
name: yyy,
subj1: [20],
subj2: [40]
}
]
}
How can I achieve this in node js. Only through looping I can do or is there an easy way I can achieve this by using libraries like lodash,underscore js.
You can use map and reduce to do something like this perhaps:
let sampleData = {
data:[{
name: "xxx",
createdDate:10/01/2018,
subj1:20,
subj2:40
},
{
name: "xxx",
createdDate:10/11/2017,
subj1:40,
subj2:70
},
{
name: "yyy",
createdDate:10/01/2018,
subj1:20,
subj2:40
}]
};
let sorted = sampleData.data.sort((element1, element2) => {
return element1.name <= element2.name ? -1 : 1
}).reduce((accumulator, currentValue, currentIndex, array) => {
if (accumulator.data.length == 0){
accumulator.data.push({name:currentValue.name, subj1:[currentValue.subj1], subj2:[currentValue.subj2]});
return accumulator;
} else {
if (accumulator.data[accumulator.data.length - 1].name == currentValue.name){
accumulator.data[accumulator.data.length - 1].subj1.push(currentValue.subj1);
accumulator.data[accumulator.data.length - 1].subj2.push(currentValue.subj2);
} else {
accumulator.data.push({name:currentValue.name, subj1:[currentValue.subj1], subj2:[currentValue.subj2]});
}
return accumulator;
}
}, {data:[]})
console.log(sorted)

Categories