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);
Related
i have two arrays Here, alreadyAddedAreas is single Array and areasData is a nested Array- Here areasData look like this.Here what i want to return data Like in same structure as Areas Data and add isAdded property if its present in alreadyAddedAreas
const areasData=[
countries: [
{
id: 123,
cities:[
{
id: 001,
areas: [{
id: 890,
}, {
id:891
}]
},
{
id: 002,
areas: [{
id: 897,
}, {
id:899
}]
},
]
}
]
]
//alreadyAddedAreas is an Array of Added Areas
const areas: [{
id: 890,
}, {
id:891
}]
// Here what i want to return data Like in same structure as Areas Data and add isAdded property if its present in alreadyAddedAreas
export const getFilteredAreasList1 = (areasData, alreadyAddedAreas) => {
const filteredArray = [];
if (areasData && alreadyAddedAreas) {
areasData[0]?.cities?.map((city) => {
return city?.areas?.map((area) => {
if (
!alreadyAddedAreas.find((item) => item?.areaID?._id === area?._id)
) {
filteredArray.push({
...area,
isAdded: false,
});
} else {
filteredArray.push({
...area,
isAdded: true,
});
}
});
});
return filteredArray;
}
};
I am having two array with the same length and format given at the end.
assume the last element on each array is the score if either array has zero values in other elements.
Let's say we have array p1 and p2 each have 7 elements. If either p1 or p2 first 6 elements has zero value then it means the game is over and we sum up all other elements and add to last element(mail_hole) which define its score. Then compare each score to find the winner.
Here is my code:
function checkWinner(holes, status = "incomplete", winner = "none") {
const p1MainHole = holes["p1"].pop(); // check if all holes has zero stone.(Except main hole)
const p2MainHole = holes["p2"].pop(); // check if all holes has zero stone.(Except main hole)
if (holes["p1"].every((hole) => hole.value === 0)) {
const sumOfAllStone = this.countAllStone(holes, "p2", p2MainHole);
holes["p2"].push(sumOfAllStone);
holes["p1"].push(p1MainHole);
status = "complete";
} else if (holes["p2"].every((hole) => hole.value === 0)) {
const sumOfAllStone = this.countAllStone(holes, "p1", p1MainHole);
holes["p1"].push(sumOfAllStone);
holes["p2"].push(p2MainHole);
status = "complete";
} else {
holes["p1"].push(p1MainHole);
holes["p2"].push(p2MainHole);
}
if (status === "complete") {
winner = holes["p1"][holes["p1"].length - 1].value > holes["p2"][holes["p2"].length - 1].value ? "p1" : "p2";
}
return {
holes,
status,
winner
};
}
function countAllStone(holes, player, mainHole) {
for (let i = 0; i < holes[player].length; i++) {
mainHole.value += holes[player][i].value;
}
return mainHole;
}
console.log(
checkWinner({
p1: [
{
name: "hole_0",
value: 0,
},
{
name: "hole_1",
value: 0,
},
{
name: "hole_2",
value: 0,
},
{
name: "hole_3",
value: 0,
},
{
name: "hole_4",
value: 0,
},
{
name: "hole_5",
value: 0,
},
{
name: "main_hole",
value: 0,
},
],
p2: [
{
name: "hole_0",
value: 1,
},
{
name: "hole_1",
value: 1,
},
{
name: "hole_2",
value: 1,
},
{
name: "hole_3",
value: 1,
},
{
name: "hole_4",
value: 2,
},
{
name: "hole_5",
value: 0,
},
{
name: "main_hole",
value: 1,
},
],
})
);
At the end it compares each player's score(last elements) to find the winner.
I am not satisfied with the amount of code written and the efficiency of it. Any idea would be welcome, Thanks.
This may be one possible alternate solution to achieve the desired objective:
Code Sample
if (allZeroValues(p1) || allZeroValues(p2)) {
resObj.status = 'complete';
if (allZeroValues(p1)) updateTotal(p2);
else updateTotal(p1);
resObj.winner = getWinner(p1, p2);
};
Explanation
if either p1 or p2 are zero-valued (except 'main_hole'), then
set status to complete
if p1 is all zeroes, update p2's total
else, update p1's total
set winner based on the totals
There are several helper methods used which may be understood from perusing the snippet below.
Code Snippet
const checkWinner = (holes, status = "incomplete", winner = "none") => {
// first, declare few helper methods
// to get an array without the 'main_hole'
const skipMainHole = arr => ([
...arr.filter(el => el.name !== 'main_hole')
]);
// add total values except 'main_hole'
const sumValues = arr => (
skipMainHole(arr).reduce(
(tot, itm) => (tot + itm.value),
0
)
);
// check if array without 'main_hole' is all zeroes
// assumption: 'value' will always be non-negative integer
const allZeroValues = arr => (sumValues(arr) === 0);
// update 'main_hole' value
const updateTotal = arr => {
arr[arr.length - 1].value += sumValues(arr);
};
// get winner
const getWinner = (arr1, arr2) => (
arr1.slice(-1)[0].value === arr2.slice(-1)[0].value
? 'none'
: arr1.slice(-1)[0].value > arr2.slice(-1)[0].value
? 'p1'
: 'p2'
);
// now, de-structure holes to get the p1, p2 arrays
const {p1, p2} = holes;
// set-up a result-object
const resObj = {status, winner};
// now, for the actual logic
if (allZeroValues(p1) || allZeroValues(p2)) {
resObj.status = 'complete';
if (allZeroValues(p1)) updateTotal(p2);
else updateTotal(p1);
resObj.winner = getWinner(p1, p2);
};
// finally, return the updated result-object
return {...resObj, holes: {p1, p2}};
};
console.log(
checkWinner({
p1: [
{
name: "hole_0",
value: 0,
},
{
name: "hole_1",
value: 0,
},
{
name: "hole_2",
value: 0,
},
{
name: "hole_3",
value: 0,
},
{
name: "hole_4",
value: 0,
},
{
name: "hole_5",
value: 0,
},
{
name: "main_hole",
value: 0,
},
],
p2: [
{
name: "hole_0",
value: 1,
},
{
name: "hole_1",
value: 1,
},
{
name: "hole_2",
value: 1,
},
{
name: "hole_3",
value: 1,
},
{
name: "hole_4",
value: 2,
},
{
name: "hole_5",
value: 0,
},
{
name: "main_hole",
value: 1,
},
],
})
);
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
I want to combine two arrays of objects, to make it easier for me to display in HTML. The function should find matching values of keys called "id" in arr1, and "source" in arr2. Here's what it looks like:
let arr1 = [
{id = 1,
name = "Anna"},
{id = 2,
name = "Chris"}
]
let arr2 = [
{childName = "Brian",
{source = 1}},
{childName = "Connie",
{source = 2}}
{childName = "Dory",
{source = 1}}
]
I tried different approaches, with best one being using forEach and filter on the arrays. I'm trying to set up a new property in arr1 objects called "children".
arr1.forEach(el => el.children = arr2.filter(checkMatch));
function checkMatch(child){
for(let i=0;i<arr1.length;i++){
child.childName.source === arr1[i].id
}
}
And this results in adding appropriate children to the first object(Anna has Brian and Dory now) so it's correct, but it also adds the same children to the second object (so Chris has also Brian and Dory).
Where is my mistake here? I'm guessing that the loop doesn't work the way I want it to work, but I don't know which one and how it happens.
Since your syntax for creating the objects of arr1 and arr2 are not valid i tried to guess the structure of your objects.
let arr1 = [
{
id: 1,
name: "Anna"
},
{
id: 2,
name: "Chris"
}
];
let arr2 = [
{
childName: "Brian",
source: 1
},
{
childName: "Connie",
source: 2
},
{
childName: "Dory",
source: 1
}
];
arr2.map((child) => {
for (let parent of arr1) {
if (parent.id == child.source) {
if (!parent.children) {
parent.children = [];
}
parent.children.push(child);
}
}
});
console.log(arr1);
There were problems with your JSON, but I tidied and here is option using map and filter
const arr1 = [{
id: 1,
name: "Anna"
},
{
id: 2,
name: "Chris"
}];
const arr2 = [{
childName: "Brian",
parent: {
source: 1
}
},
{
childName: "Connie",
parent: {
source: 2
}
},
{
childName: "Dory",
parent: {
source: 1
}
}];
let merge = arr1.map(p => {
p.children = arr2.filter(c => c.parent.source === p.id).map(c => c.childName);
return p;
});
console.log(merge);
Your json have some problems you should use
:
instead of
=
Also some Braces make the structure incorrect, but I think what you want to do here is fill a children sub array with the childNames of the subject here is my approach:
var json =
[
{
"id" : 1,
"name" : "Anna"
},
{
"id" : 2,
"name" : "Chris"
}
];
var subJson = [
{
"childName" : "Brian",
"source" : 1
},
{
"childName" : "Connie",
"source" : 2
},
{"childName" : "Dory",
"source" : 1
}
];
var newJson = [];
$.each(json,function(index1,item){
newJson.push({"id":item.id,"name":item.name, "children": []});
$.each(subJson,function(index2,subitem){
if(subitem.source == item.id){
newJson[newJson.length - 1].children.push({"childName":subitem.childName}) ;
}
})
})
console.log(newJson);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Hope it helps
The below uses Map for storage and convenient lookup of parents.
const parents = [
{
id: 1,
name: "Anna"
},
{
id: 2,
name: "Chris"
}
]
const children = [
{
childName: "Brian",
source: 1
},
{
childName: "Connie",
source: 2
},
{
childName: "Dory",
source: 1
}
]
// Create a map for easy lookup of parents.
const parentMap = new Map()
// Add parents to the map, based on their id.
parents.forEach(parent => parentMap.set(parent.id, parent))
// Add children to their parents.
children.forEach((child) => {
// Get the parent from the map.
const parent = parentMap.get(child.source)
// Handle parent not found error.
if (!parent) { return console.error('parent not found for', child.childName)}
// Create the children array if it doesn't already exist.
parent.children = parent.children || []
// Add the child to the parent's children array.
parent.children.push(child)
})
// Output the result.
Array.from(parentMap).forEach(parent => console.log(parent[1]))
Result:
{
id: 1,
name: 'Anna',
children: [
{ childName: 'Brian', source: 1 },
{ childName: 'Dory', source: 1 }
]
}
{
id: 2,
name: 'Chris',
children: [
{ childName: 'Connie', source: 2 }
]
}
I have a few questions in regards to what would be the best approach to do the following:
Call two different API:
axios.get(contents);
axios.get(favorites);
Response will Look like this:
contents: [
{
id: 1,
value: someValue
},
{
id: 2,
value: someValue
}
];
favorites: [
{
id: 1,
contentId: 2
}
];
What would be the best approach to loop through each favorite and add an element to the contens array such as isFavorite: true when the contentId matches the id. It should look as follows:
contents: [
{
id: 1,
value: someValue
{,
{
id: 2,
value: someValue
isFavorite: true
{
];
What would be the best place to do this and is there any ES6 syntax that can easily do this? I currently have the two actions separate, one that gets the contents and one that gets the favorites, I could possibly merge those or combine them at the reducer.
Any suggestions?
You can use a Set to collect all contentId values from favorites and then iterate through your contents array. This has better time complexity than using some on an array because calling .has() on a Set is O(1):
let contents = [{
id: 1,
value: 'someValue1'
},
{
id: 2,
value: 'someValue2'
},
{
id: 3,
value: 'someValue'
}
];
let favorites = [{
id: 1,
contentId: 2
},
{
id: 2,
contentId: 3
}
];
let favoriteContents = new Set(favorites.map(f => f.contentId));
contents.forEach(c => {
if (favoriteContents.has(c.id)) c.isFavorite = true;
});
console.log(contents);
const newContents = contents.map((content) => {
const foundFavorite = favorites.find((favorite) => favorite.contentId === content.id)
if (foundFavorite) {
return {
...content,
isFavorite: true,
}
}
return content
});
You firstly need to have the promises from your API calls, and when both of them are complete you can then carry out the merge of the results.
const contentsApi = () => Promise.resolve([
{
id: 1,
value: 'foo'
},
{
id: 2,
value: 'bar'
}
])
const favouritesApi = () => Promise.resolve([
{
id: 1,
contentId: 2
}
])
let contents;
let favourites;
const contentsApiCall = contentsApi().then(res => {
contents = res;
})
const favouritesApiCall = favouritesApi().then(res => {
favourites = res;
})
Promise.all([contentsApiCall, favouritesApiCall]).then(() => {
const merged = contents.map(content => {
if(favourites.some(favourite => favourite.contentId === content.id)){
return {
...content,
isFavourite: true
}
} else {
return content;
}
})
console.log(merged)
// do whatever you need to do with your result, either return it if you want to chain promises, or set it in a variable, etc.
})