Related
I am making web pages through Next.js and Recoil.
I'm making global data for the problem through recoil, but I don't know how to get the value in the 3rd depth.
export const surveyState = atom<ISurveyData>({
key: "surveyState",
default: {
id: 0,
subject: "",
content: "",
startDate: "",
endDate: "",
minute: 0,
openFl: 1,
tempFl: 1,
closingComment: "",
hashtag: [],
sections: [
{
title: "",
content: "",
nextSection: -1,
questions: [ //I want to get the number of this attribute.
{
ask: "",
explain: "",
multiFl: 1,
essFl: 0,
dupFl: 0,
oder: 0,
questionItems: [{ content: "", oder: 0, nextSection: 0 }],
},
],
},
],
},
});
//I want to import it as a selector like this.
export const partCountState = selector({
key: "partCount",
get: ({ get }) => {
const survey = get(surveyState);
return survey.sections.length;
},
});
I want to get the length of the questions in each section.
Each index of the sections can have different lengths of qusetions, how can I get them into a selector?
This is intended to show the total number of problems.
I have two versions for the same logic. Below are the two codes:
/*Code 1*/
this.state.dataModel[0].route.routeLine = this.props.routeLine.join(' ');
/*Code 2*/
this.setState(prevState => {
const newDataModel = [...prevState.dataModel];
newDataModel[0].route.routeLine = this.props.routeLine.join(' ');
return {dataModel: newDataModel};
});
/* Common Code */
let finalData = { ...this.state.dataModel[0],
hasLocationChanged: this.state.isLocationEditedForConsSeg };
let data = JSON.stringify(finalData)
console.log('Stringify Data ',JSON.stringify(data))
When I use Code 1 the object is converted to JSON strings without data loss. But if I use Code 2 I am loosing data in JSON strings when using JSON.stringify().But according to my understanding of react Code 1 is not the correct way to mutate state
Below is the finalData in JSON object:
{
"layer": 1,
"layerName": "ConstructionSegment",
"layerId": 7384,
"agencyId": 79,
"lpModel": {
"lastProjectType": 2,
"lastProjectSurf": 2,
"gravelType": 0,
"gravelTreatment": 0,
"bitType": 1,
"concrType": 0,
"astType": 0,
"compType": 0,
"lastProjectYear": 2002,
"lpDepth": 7,
"totalDepth": 7,
"lastProjectMile": "0",
"comment": "",
"lastProjectYearEst": 0,
"lpDepthEst": 0,
"totalDepthEst": 0
},
"bModel": {
"topBaseType": 3,
"topBaseDpt": 23,
"topBaseYear": 1973,
"topBaseTrt": 6,
"bottomBaseType": 2,
"bottomBaseDpt": 23,
"bottomBaseYear": 0,
"bottomBaseTrt": 1,
"fabric": 0,
"subgradeStrength": 100,
"subgradeStrengthType": 5,
"lastSGImpYear": 0,
"subgradeTrt": 1,
"topBaseTypeEst": 0,
"topBaseDptEst": 0,
"topBaseYearEst": 0,
"bottomBaseTypeEst": 0,
"bottomBaseDptEst": 0,
"bottomBaseYearEst": 0,
"subgradeStrengthEst": 0,
"lastSGImpYearEst": 0
},
"xModel": {
"laneWidth": 4,
"numLanes": 2,
"rtShoulderTotal": 5,
"rtShoulderPaved": 0,
"gradingYear": 1973,
"curbs": 0,
"inslopeRatio": 0,
"paveSloughWidth": 0,
"sloughRatio": 0,
"edgelineTrt": 0,
"centerlineTrt": 0,
"medianType": 0,
"medianWidth": 0,
"rightOfWay": 100,
"sectionOwner": 2,
"gradingYearEst": 0
},
"maintenance": {
"blade": [],
"regravel": [],
"reshape": [],
"spotRep": [],
"dustControl": [],
"surfacing": [],
"crackSeal": [],
"patching": [],
"striping": [],
"cpr": [],
"crackSealConcrete": [],
"reApplyAst": []
},
"pavementcondition": {
"PlannedProjType": 0
},
"route": {
"id": 12804,
"start": "47.04905, -95.722035",
"end": "47.107359, -95.721154",
"routeLength": "4.03",
"routeArray": [
"47.04906,-95.72206",
"47.06001,-95.72184",
"47.06281,-95.72179",
"47.07266,-95.7216",
"47.07647,-95.72154",
"47.07991,-95.72149",
"47.08224,-95.72154",
"47.08528,-95.72169",
"47.08749,-95.72178",
"47.08846,-95.72179",
"47.09029,-95.72181",
"47.09236,-95.72178",
"47.09425,-95.72172",
"47.09729,-95.72154",
"47.10185,-95.721",
"47.10291,-95.72095",
"47.10738,-95.72119"
],
"routePointArray": [
[
47.04906,
-95.72206
],
[
47.06001,
-95.72184
],
[
47.06281,
-95.72179
],
[
47.07266,
-95.7216
],
[
47.07647,
-95.72154
],
[
47.07991,
-95.72149
],
[
47.08224,
-95.72154
],
[
47.08528,
-95.72169
],
[
47.08749,
-95.72178
],
[
47.08846,
-95.72179
],
[
47.09029,
-95.72181
],
[
47.09236,
-95.72178
],
[
47.09425,
-95.72172
],
[
47.09729,
-95.72154
],
[
47.10185,
-95.721
],
[
47.10291,
-95.72095
],
[
47.10738,
-95.72119
]
],
"startPoint": [
[
47.04905,
-95.72204
]
],
"endPoint": [
[
47.10736,
-95.72115
]
],
"waypoints": [],
"isPolyLine": false,
"hwyNum": "34",
"segDesc": "",
"routeLine": "47.04906,-95.72206 47.06001,-95.72184 47.06281,
-95.72179 47.07266,-95.7216 47.07647,
-95.72154 47.07991,-95.72149 47.08224,-95.72154 47.08528,
-95.72169 47.08749,-95.72178 47.08846,-95.72179 47.09029,
-95.72181 47.09236,-95.72178 47.09425,
-95.72172 47.09729,-95.72154 47.10185,-95.721 47.10291,
-95.72095 47.10738,-95.72119"
}
}
I can see the data routeLine in the console.log() statement if I use Code 1 but I cannot see the data routeLine in the console.log() if I use Code 2
You are losing it becasue setState is asynchronous. If you call this.setState and soon after you read this.state you'll notice that it's not immediately updated.
See this question for further details please and setState docs.
edit1: I created a sandbox example for you. Check code in App.js, you'll se 4 click functions and a logState function. click1 and click2 do what you did in your original post, click3 and click4 propose a solution to overcome the problem.
Your routeLine is a string: "47.04906,-95.72206 47.06001,-95.72184 47.06281", not an array as you might think. You need to first convert it to an array, and then apply a join():
this.state.dataModel[0].route.routeLine.split(' ').join(). You might need to revise your state and make sure you are parsing data according to your expectations.
I'm trying to update the objects that is in the nested array, below is an example of my state. I am trying to update the objects within goals I succeed with updating the objects.
BUT
Each time I update any object. the object at index 0, will get a copy of all the objects. And the more times I update, it creates more copies and they become nested within the object at index 0.
The object at index 0 will also be updated with the most recent update of any object.
{
list: {
'0': {
id: 0,
dueDate: 'By May 28th I Will have: ',
goals: [
{
0: {...}
1: {...}
3: {...}
}
]
}
'1':{
id: 0,
dueDate: 'By June 31st I Will have: ',
goals: [
{
2: {...}
4: {...}
}
}
keyName = index of object in list. ( the two ones above '0' and '1' : {
)
Reducer
return {
...state,
[action.payload.keyName]: {
...state[action.payload.keyName],
goals: [
{ ...state[action.payload.keyName].goals, ...action.payload.goal },
...state[action.payload.keyName].goals.slice(1, state[action.payload.keyName].goals.length)
]
}
};
Also if you know any good documentation or tutorial on normalizr please let me know.
Thank you in advance! :)
This will update a goal based in its keys, assuming a goal has unique keys.
const state = {
'0': {
id: 0,
dueDate: 'By May 28th I Will have: ',
goals: [
{a: 1,
b: 1,
c: 1}
]
},
'1':{
id: 0,
dueDate: 'By June 31st I Will have: ',
goals: [
{d: 1,
r: 1}
]
}
};
function reducer(state, keyName = 0, goal) {
const goals = [...state[keyName].goals];
const index = state[keyName].goals.findIndex((e) => Object.keys(e).every((key) => Object.keys(goal).includes(key)));
goals.splice(index,1, goal);
return {
...state,
[keyName]: {
...state[keyName],
goals,
}
};
}
console.log(reducer(state, 0, {a:3, b:2, c:4}));
This is assuming that you are updating your goals by array positioning.
const state = {
'0': {
id: 0,
dueDate: 'By May 28th I Will have: ',
goals: [
{test: 1},
{test: 1},
{test: 1}
]
},
'1':{
id: 0,
dueDate: 'By June 31st I Will have: ',
goals: [
{test: 1},
{test: 1}
]
}
};
function reducer(state, keyName = 0, goal) {
return {
...state,
[keyName]: {
...state[keyName],
goals: [{...state[keyName].goals, ...goal}]
}
};
}
console.log(reducer(state, 0, [{test:3}, {test:44}]));
Johan looks like you desctucture your state in a wrong way.
First, try to update your goals using array desctucturing goals: [{...state[keyName].goals, ...newGoal}]
And also maybe this one might come useful https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns#updating-nested-objects
Say I have a lot of the following documents:
{
_id: “abc”,
values: {
0: { 0: 999999, 1: 999999, …, 59: 1000000 },
1: { 0: 2000000, 1: 2000000, …, 59: 1000000 },
…,
58: { 0: 1600000, 1: 1200000, …, 59: 1100000 },
59: { 0: 1300000, 1: 1400000, …, 59: 1500000 }
}
}
{
_id: “def”,
values: {
0: { 0: 999999, 1: 999999, …, 59: 1000000 },
1: { 0: 2000000, 1: 2000000, …, 59: 1000000 },
…,
58: { 0: 1600000, 1: 1200000, …, 59: 1100000 },
59: { 0: 1300000, 1: 1400000, …, 59: 1500000 }
}
}
which is basically a multidimensional array of 60x60 items.
can aggregation (or any other mongodb construct) be used to easily sum the two (or more) matrixes? i.e. values[x][y] of both abc and def are summed together, and the same is done for all other elements?
Ideally the output would be a similar multidimensional array.
This answer seems to suggest this is possible with 1 dimensional array but I am not sure for multidimensional.
EDIT:
This is an example with real data in a format which is slightly different:
db.col.find({}, { _id: 0, hit: 1 })
{ "hit" : [ [ 570, 0, 630, 630, 636, 735, 672, 615, 648, 648, 618, 0 ],
[ 492, 0, 471, 471, 570, 564, 0, 590, 513, 432, 471, 477 ],
[ 387, 0, 0, 0, 0, 0, 0, 456, 0, 480, 351, 415 ],
[ 432, 528, 0, 0, 495, 509, 0, 579, 0, 552, 0, 594 ],
[ 558, 603, 594, 624, 672, 0, 0, 705, 783, 0, 756, 816 ],
[ 0, 858, 951, 1027, 0, 0, 1058, 1131, 0, 0, 1260, 1260 ],
[ 1269, 0, 1287, 0, 1326, 0, 1386, 1386, 1470, 0, 0, 0 ],
[ 1623, 0, 1695, 1764, 1671, 1671, 0, 1824, 1872, 0, 0, 0 ],
[ 1950, 1894, 2034, 2034, 0, 0, 1941, 0, 2070, 1911, 2049, 2055 ],
[ 2052, 2052, 0, 0, 0, 2085, 2007, 2073, 0, 0, 0, 1941 ],
[ 1878, 1896, 0, 1875, 0, 0, 1677, 0, 1722, 0, 1545, 0 ],
[ 0, 0, 1317, 1469, 1501, 1634, 1494, 0, 0, 1290, 0, 0 ],
[ 0, 1485, 1375, 1491, 1530, 1407, 0, 0, 0, 1611, 0, 0 ],
[ 1652, 1800, 1686, 1643, 1923, 0, 0, 0, 1737, 1604, 1797, 0 ],
[ 1842, 1806, 0, 1830, 1896, 1947, 0, 1710, 1734, 1725, 0, 0 ],
[ 0, 0, 1932, 0, 1908, 1878, 1941, 1931, 2007, 2013, 1995, 1995 ],
[ 0, 2025, 2004, 1927, 0, 0, 1939, 1835, 1962, 1863, 0, 1815 ],
[ 0, 0, 1839, 1755, 1821, 1821, 1751, 1656, 0, 0, 1467, 0 ],
[ 0, 1632, 1546, 1449, 0, 1551, 1449, 0, 0, 1554, 0, 1491 ],
[ 1463, 1411, 0, 1491, 0, 0, 1551, 1467, 0, 0, 0, 1464 ],
[ 0, 0, 1311, 0, 0, 1471, 0, 0, 1581, 0, 1368, 1368 ],
[ 1296, 0, 0, 0, 1176, 1381, 0, 1170, 1194, 1194, 1193, 1137 ],
[ 0, 1244, 1221, 1039, 0, 1041, 930, 921, 1033, 813, 0, 0 ],
[ 0, 0, 0, 1010, 0, 0, 918, 783, 0, 609, 693, 645 ] ] }
And this is the appropriate query (thanks to Veeram in the comments for fixing my code):
db.col.aggregate([
{ $project: { _id: 0, hit: 1 } },
{ $unwind: { path: "$hit", includeArrayIndex: "x" } },
{ $unwind: { path: "$hit", includeArrayIndex: "y" } },
{ $group: { _id: { x: "$x", y: "$y" }, hit: { $sum: "$hit" } } },
{ $sort: { "_id.x": 1, "_id.y": 1 } },
{ $group: { _id: "$_id.x", hit: { $push: "$hit" } } },
{ $sort: { "_id": 1 } },
{ $group: { _id: null, hit: { $push: "$hit" } } }
])
You need two operators to deal with dynamic properties: $objectToArray and $arrayToObject. To sum the values from all documents you can try to represent each x,y pair as single document (using $unwind) and then use several $group stages to get single document as a result. To get the initial order of your rows and columns you can apply $sort twice:
db.col.aggregate([
{
$project: {
values: {
$map: {
input: { $objectToArray: "$values" },
as: "obj",
in: { k: "$$obj.k", v: { $objectToArray: "$$obj.v" } }
}
}
}
},
{
$unwind: "$values"
},
{
$unwind: "$values.v"
},
{
$project: {
x: "$values.k",
y: "$values.v.k",
value: "$values.v.v"
}
},
{
$group: {
_id: { x: "$x", y: "$y" },
value: { $sum: "$value" }
}
},
{
$sort: {
"_id.y": 1
}
},
{
$group: {
_id: "$_id.x",
v: { $push: { k: "$_id.y", v: "$value" } }
}
},
{
$sort: {
"_id": 1
}
},
{
$group: {
_id: null,
values: { $push: { k: "$_id", v: "$v" } }
}
},
{
$project: {
values: {
$arrayToObject: {
$map: {
input: "$values",
as: "obj",
in: {
k: "$$obj.k",
v: { $arrayToObject: "$$obj.v" }
}
}
}
}
}
}
])
For your sample data it outputs:
{
"_id" : null,
"values" : {
"0" : {
"0" : 1999998,
"1" : 1999998,
"59" : 2000000
},
"1" : {
"0" : 4000000,
"1" : 4000000,
"59" : 2000000
},
"58" : {
"0" : 3200000,
"1" : 2400000,
"59" : 2200000
},
"59" : {
"0" : 2600000,
"1" : 2800000,
"59" : 3000000
}
}
}
Take a look at this array:
const int *c000[64][1][3] =
{
//Row 1
{ {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} },
//Row 2
{ {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} },
//Row 3
{ {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} },
//Row 4
{ {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} },
//Row 5
{ {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} },
//Row 6*
{ {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} },
//Row 7
{ {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} },
//Row 8
{ {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} }, { {0, 0, 0} },
};
Ignore the strange size and structure of the array, that's not what is important. I need to be able to use an array inside this array. For example, I have an array called h002:
const int h002[18] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0xe0, 0xe0}; //01
I need to be able to use h002 from inside c000. Such as:
{ {h002, 0, 0} },
This compiles just fine, however
myVar = c000[0][0][0];
retrieves the address of h002. I need the first item in h002, not the address. I'm confused as to why it would even give me the adress of h002 at all? I would imagine *h002 would retrieve the address, but then that doesn't compile at all.
I have seen several questions on SO that closely resemble mine, such as this one:
Creating an array of int arrays in C?
I have tried that particular example above. It works when I have it in my main.c file, but when I try it in the same .c file that c000 and h002 are contained in, it fails to compile. Perhaps this has something to do with it? I'm not sure why it would, considering using h002 inside c000 returns the address of h002 just fine. It's strange that the code presented in the link above wouldn't compile outside of my main file.
I feel like I'm making some kind of obvious, little mistake. I've been messing around with this off and on for about 5 days now. Trial and error and research has gotten me nowhere. Researching was difficult enough, as there doesn't seem to be much on using arrays like this, and none of my findings significantly helped me.
Feel free to ask questions. I'll be glad to specify more information if needed.
EDIT: Thanks so much to Stephan Lechner for helping me solve my issue. To get the result I needed, I had to do
myVar = *(c000[0][0][0]);
This works perfectly. I can also add whatever number I like at the end to retrieve different indexes in h002. For example:
myVar = *(c000[0][0][0] + 7);
Hope this helps someone out in the future.
I think the basic misunderstanding is the meaning of const int *c000[64][1][3], which denotes a three dimensional array of pointers to int, but not a pointer to an 3D-array of integers. To demonstrate this, consider the following simplified examples together with compiler warnings:
int aSingleIntValue = 10; // integer value
int *aSinglePtrToIntValue = &aSingleIntValue; // pointer to an integer value
// 1D-array of integer values
int oneDArrayOfInt[5] = { 3,4,5,6,7 };
// 1D-array of pointers to int; Note: OK, since 0 is interpreted as NULL
int *oneDArrayOfIntPtrOK[5] = { aSinglePtrToIntValue,0,0,0,0 };
// 1D-array of pointers to int; Note: 3,4,.. are int values, not pointers to int; Hence compiler complains:
// Warning: Incompatible integer to pointer conversion initializing "int *" with an expression of type "int"
int *oneDArrayOfIntPtrWarning[5] = { 3,4,5,6,7 };
// 3D-array of pointers to int; Note: OK, since 0 is interpreted as NULL
int *threeDArrayOfIntPtrOK[5][5][5] = { { { aSinglePtrToIntValue,0,0 }, { 0,0,0} } };
// 3D-array of pointers to int; Warining: Incompatible integer to pointer conversion initializing "int *" with an expression of type "int"
int *threeDArrayOfIntPtrWarning[5][5][5] = { { { 3,4,5 }, { 2,3,1} } };
Just for showing a different meaning: if one would like to declare a pointer to an array of 5 integers, this could be expressed as follows:
typedef int arrayOf5Int_t[5];
arrayOf5Int_t *arrayOf5IntPtr = &oneDArrayOfInt;
Given that, let's explain the meaning of
const int h002[18] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0xe0, 0xe0};
const int *c000[64][1][3] = { { { h002, 0, 0 } } };
Note that an element of c000 is a pointer to an integer, and note that variable h002 used in the context of the array initialiser decays to a pointer to an integer (pointing to the first element of h002). This is pretty much the same as declaring const int* ptrToH002 = h002, and the following print out demonstrates that this is actually the same:
const int *elemAt0x0x0 = c000[0][0][0];
const int *ptrToH002 = h002;
int isTheSame = elemAt0x0x0 == ptrToH002;
printf("pointer elemAt0x0x0 == ptrToH002 is %s", (isTheSame ? "true" : "false"));
// Prints: pointer elemAt0x0x0 == ptrToH002 is true
Hence, it should be clear that myVar = c000[0][0][0] retrieves an address, and not an integer value or an integer array. The address points to the first element of array h002.
Example of multidimensional array:
int main(){
int a1[] = {1,2,3,4};
int a2[] = {5,6,7,8};
int a3[] = {9,10,11,12};
int * superArr[3] = {a1,a2,a3};
printf("%d\n", superArr[2][1]);
}
You should be able to change your code to what you need using this example.