Pushing items from first array of objects to another array of objects - reactjs

defaultParameterTypes = [] // this is my empty array
const propsArray = this.props.device.deviceProperties.defaultParameterTypes;
const defaultParameterTypes = this.state.deviceSettings.defaultParameterTypes;
when i checked on checkbox i want to push into my defaultParameterTypes array the object but the case is
when the type is repeated dont push it twice.
"propsArray": "[{'name': '1','type': '11'}, {'name': '2','type': '22'}, {'name': '3','type': '11'}, {'name': '4','type': '11'}, {'name': '5','type': '22'}, {'name': '6','type': '22'}, {'name': '7','type': '22'}]",
i want to make like loop and check if it is not found in defaultEmptyArray and push it if not found
but i dont need the type to be repeated in mydefaultarray

Simple way would be to create a map of the types seen in the array and reduce your input array into it, then get the array of values from the map you created.
const data = [
{ name: "1", type: "11" },
{ name: "2", type: "22" },
{ name: "3", type: "11" },
{ name: "4", type: "11" },
{ name: "5", type: "22" },
{ name: "6", type: "22" },
{ name: "7", type: "22" }
];
// reduce array into map of type => { name, type }
// then get the object values array
const reducedData = Object.values(
data.reduce((acc, { name, type}) => {
if (!acc[type]) acc[type] = { name, type }; // if not seen type, store
return acc;
}, {})
);
console.log(reducedData)
Expand on this concept to create a function that takes two arrays and processes the second into the first.
const data = [
{ name: "1", type: "11" },
{ name: "2", type: "22" },
{ name: "3", type: "44" },
{ name: "4", type: "11" },
{ name: "5", type: "22" },
{ name: "6", type: "33" },
{ name: "7", type: "22" }
];
const data2 = [
{ name: "1", type: "33" },
{ name: "2", type: "22" },
{ name: "3", type: "66" },
{ name: "4", type: "11" },
{ name: "5", type: "22" },
{ name: "6", type: "44" },
{ name: "7", type: "22" }
];
const data3 = [
{ name: "1", type: "66" },
{ name: "2", type: "22" },
{ name: "3", type: "33" },
{ name: "4", type: "11" },
{ name: "5", type: "55" },
{ name: "6", type: "11" },
{ name: "7", type: "44" }
];
const reduceData = (currentArray = [], newArray = []) => {
const mapFn = (acc, { name, type }) => {
if (!acc[type]) acc[type] = { name, type }; // if not seen type, store
return acc;
};
const createMap = array => array.reduce(mapFn, {});
return Object.values(newArray.reduce(mapFn, createMap(currentArray)));
};
const reducedData = reduceData(data, data2);
const reducedData1 = reduceData(reducedData, data3);
console.log(reducedData);
console.log(reducedData1);

let hasValue = (arr, obj) => arr && arr.filter(item => item.type == obj.type).length
let result = propsArray.reduce((acc, curr) => {
if (hasValue(acc, curr)) {
return acc;
} else {
return [...acc, curr]
}
}, []);
will give u an array with all the elements where the type property is unique..
hope this is what ur expected result..
let result = propsArray.reduce((acc, curr) => {
if (hasValue(acc, curr)) {
return [...acc, { name: curr.name }];
} else {
return [...acc, curr]
}
}, []);
or if type reccurs, copy only the name object..
this will return an array of same length but along the elements, type property will be removed if it recurrs...

Related

REACT: Updating nested state

I have two sets of data. Both are saved in a states.I want to update the rowsData inside the data1 state based on the values in data2 state. The "row" value in the data2 object refers to the "id" of rowsData in the data1 state and columns in the data2 refers to any data beside id in the rowsData object in data1. I want to pick "row" and "column" from data2 and cahnge the respective data inside rowsData in data1.
let tableData = {
columnsDef: [
{ title: "id",field: "id",className: "header-style" },
{ title: "First_name", field: "First_name", className: "header-style" },
{ title: "Last_name", field: "Last_name", className: "header-style" },
{ title: "Email", field: "Email", className: "header-style" },
],
rowsData:[
{ id: "1", First_name: "Donald", Last_name: "OConnell", Email: "DOCONNEL" },
{ id: "2", First_name: "Douglas", Last_name: "Grant", Email: "DGRANT" },
{ id: "3", First_name: "Jennifer", Last_name: "Whalen", Email: "JWHALEN" },
{ id: "4", First_name: "Michael", Last_name: "Hartstein", Email: "MHARTSTE" },
{ id: "5", First_name: "Pat", Last_name: "Fay", Email: "PFAY" },
{ id: "6", First_name: "Susan", Last_name: "Mavris", Email: "SMAVRIS" },
{ id: "7", First_name: "Hermann", Last_name: "Baer", Email: "HBAER" }
],
file: [
{ file: { path: "dummy_data_3 .csv"}}
],
}
let updatedTableData = [
{ "row": 2, "column": "Email", "oldValue": "DGRANT", "newValue": "DGRANT UPDATED" },
{ "row": 6, "column": "First_name", "oldValue": "Susan", "newValue": "SUSAN UPDATED" },
{ "row": 4, "column": "Last_name", "oldValue": "Hartstein", "newValue": "Hartstein UPDATED" }
]
const [data1, setData1] = useState(tableData)
const [data2, setData2] = useState(updatedTableData)
Here is the codesandbox link for the issue.
https://codesandbox.io/s/reverent-firefly-r87huj?file=/src/App.js
You can follow these steps for updating data1 from handleAppyChanges function:
Create a copy of rowsData:
const td = [...data1.rowsData];
Iterate over data2 and find related item, then update its related column:
data2.forEach((item) => {
let row = data1.rowsData.find((r) => r.id === item.row);
if (row) {
let index = data1.rowsData.findIndex((v) => v === row);
row[item.column] = item.newValue;
td[index] = row;
}
});
Update table data via state:
const newData = {
file: data1.file,
rowsData: td,
columnDef: data1.columnsDef
};
setData1(newData);
Here's the full function:
const handleAppyChanges = () => {
const td = [...data1.rowsData];
data2.forEach((item) => {
let row = data1.rowsData.find((r) => r.id === item.row);
if (row) {
let index = data1.rowsData.findIndex((v) => v === row);
row[item.column] = item.newValue;
td[index] = row;
}
});
const newData = {
file: data1.file,
rowsData: td,
columnDef: data1.columnsDef
};
setData1(newData);
console.log("Updated Data 1: ", td);
};
You can access the full code via codesandbox:
Apply into onChange and check it.
const handleAppyChanges = () => {
data2.map((item) => {
data1.rowsData.map((data) => {
//match both id and row
if (data.id == item.row) {
//check column is there or not
let column = data.hasOwnProperty(item.column);
if (column) {
//if yes then change the value
data[item.column] = item.newValue;
}
}
});
});
setData1({ ...data1 });
};

Remove object in array

I have a array object and a array.
const arr1=[
{ name: "viet" },
{ name: "hai" },
{ name: "han" }
]
const arr2= ["viet", "hai"];
How can i compare and set arr like:
arr = [{name: "han"}]
Try this code :D
const arr1=[
{ name: "viet" },
{ name: "hai" },
{ name: "han" }
]
const arr2= ["viet", "hai"];
const result = arr1.filter(item => !arr2.includes(item.name))
console.log(result) // [{name: "han"}]
const arr1=[
{ name: "viet" },
{ name: "hai" },
{ name: "han" }
]
const arr2= ["viet", "hai"];
let res = arr1.filter(function (n) {
return !this.has(n.name);
}, new Set(arr2));
console.log(res);

Grouping Data in TypeScript Array

I have JSON data that looks like this:
[
{
"id": 1,
"tags": [
"Test 1",
"Test 2",
"Test 3"
]
},
{
"id": 2,
"tags": [
"Test 2",
"Test 3",
"Test 4"
]
},
{
"id": 3,
"tags": [
"Test 3",
"Test 4"
]
}
]
I would like to transform this into data that looks like this:
[
{
"name": "Test 1",
"count": 1
},
{
"name": "Test 2",
"count": 2
},
{
"name": "Test 3",
"count": 3
},
{
"name": "Test 4",
"count": 1
}
]
I can think of some brute ways to do this, but I'm hoping there is something more performant and a little sexier? Possibly using .groupBy() or .reduce()?
Thanks for taking the time to check out my question.
I would:
parse the json
gather all tags in an array
count occurences using one of the approaches in Counting the occurrences / frequency of array elements
interface Item {
id: number,
tags: string[]
}
function countOccurences(a: string[]) {
return a.reduce(function (acc: {[key: string]: number}, curr: string) {
acc[curr] ??= 0;
acc[curr]++;
return acc;
}, {});
}
const data: Item[] = JSON.parse(json);
const tagOccurences = countOccurences(data.flatMap(o => o.tags))
Playground link
You can use reduce inside reduce to group the tags.
const array = [{
id: 1,
tags: ['Test 1', 'Test 2', 'Test 3'],
},
{
id: 2,
tags: ['Test 2', 'Test 3', 'Test 4'],
},
{
id: 3,
tags: ['Test 3', 'Test 4'],
},
];
const frequencies = Object.values(array.reduce((acc, curr) =>
curr.tags.reduce(
(nAcc, tag) => ((nAcc[tag] ??= {name: tag,count: 0}),nAcc[tag].count++,nAcc),
acc
), {}
));
console.log(frequencies);
In TypeScript:
const array = [{
id: 1,
tags: ['Test 1', 'Test 2', 'Test 3'],
},
{
id: 2,
tags: ['Test 2', 'Test 3', 'Test 4'],
},
{
id: 3,
tags: ['Test 3', 'Test 4'],
},
];
type Frequency = {
name: string,
count: number
}
const frequencies = Object.values(array.reduce((acc, curr) =>
curr.tags.reduce(
(nAcc, tag) => ((nAcc[tag] ??= {name: tag,count: 0}),nAcc[tag].count++,nAcc),
acc
), {} as Record<string, Frequency>
));
console.log(frequencies);
Playground
Using for...of iteration and a Map as a cache is a very straightforward approach... and sexy.
TS Playground
type TagsWithId = {
id: number;
tags: string[];
};
type TagCount = {
count: number;
name: string;
};
function verySexyTagCounter (input: TagsWithId[]): TagCount[] {
const map = new Map<string, number>();
for (const {tags} of input) {
for (const name of tags) {
map.set(name, (map.get(name) ?? 0) + 1);
}
}
return [...map.entries()].map(([name, count]) => ({name, count}));
}
const json = `[{"id":1,"tags":["Test 1","Test 2","Test 3"]},{"id":2,"tags":["Test 2","Test 3","Test 4"]},{"id":3,"tags":["Test 3","Test 4"]}]`;
const input: TagsWithId[] = JSON.parse(json);
const result = verySexyTagCounter(input);
console.log(result);

How to modify Array on React

In api return value like this,
[
"Action",
"Comedy",
"Documentary",
"Drama"
]
I need to modify the above array like this,
const techCompanies = [
{ label: "Action", value: 1 },
{ label: "Comedy", value: 2 },
{ label: "Documentary", value: 3 },
{ label: "Drama", value: 4 }
];
I used Axios to get data,
const response = await axios.get("http://localhost:3000/Movie/v1.0/genre");
This is an array so you can you use the .map() function to do that:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
const arr = ["Action", "Comedy", "Documentary", "Drama"];
arr.map((arrElement, index) => ({ label: arrElement, value: index }));

Filter Array of Object from another Array of Object

Currently I'm filtering data based from questions that have checked property value equals to true..
const data = [
{Name: "foo", X1: "1", X2: "1", Other: "Test1"},
{Name: "bar", X1: "2",X2: "2",Other: "Test2"},
{Name: "test",X1: "2",X2: "3",Other: "Test3"}
];
const questions = [{rows: {text: "Text 1", checked: true,fields: "1",column: "X1"}
}, {rows: {text: "Text 2", checked: true,fields: "2",column: "X1"}
}, {rows: {text: "Text 3", checked: false,fields: "1",column: "X2"}
}, {rows: {text: "Text 4", checked: false,fields: "2",column: "X2"}
}, {rows: {text: "Text 5", checked: false,fields: "3",column: "X2"}
}];
console.log(questionArr);
// console.log(dataArr);
const res = data.filter(d => questions.find(f => d[f.rows.column] === f.rows.fields && f.rows.checked));
which works but does not work when filtering the actual data below. I think there's a slight difference between the question object and the actual question object below.. What should be my filter code when accessing these kind of structure ?
I think this is what you're looking for. I matched the data structure to the image in your question. Let me know if I missed something.
const data = [
{ Name: "foo", X1: "1", X2: "1", Other: "Test1" },
{ Name: "bar", X1: "2", X2: "2", Other: "Test2" },
{ Name: "test", X1: "2", X2: "3", Other: "Test3" }
];
const questions = [
{ rows: [{ text: "Text 1", checked: true, fields: "2", column: "X1" }] },
{ rows: [{ text: "Text 2", checked: true, fields: "2", column: "X1" }] },
{ rows: [{ text: "Text 3", checked: false, fields: "1", column: "X2" }] },
{ rows: [{ text: "Text 4", checked: false, fields: "2", column: "X2" }] },
{ rows: [{ text: "Text 5", checked: false, fields: "3", column: "X2" }] }
];
const result = data.filter(function(item){
return questions.some(function(question){
return question.rows.some(function(row){
return (row.checked && item[row.column] === row.fields);
});
});
});
console.log(result);
The compact version
const result = data.filter((item) => questions.some((question) => question.rows.some((row) => (row.checked && item[row.column] === row.fields))));
With perf in mind
const data = [
{ Name: "foo", X1: "1", X2: "1", Other: "Test1" },
{ Name: "bar", X1: "2", X2: "2", Other: "Test2" },
{ Name: "test", X1: "2", X2: "3", Other: "Test3" }
];
const questions = [
{ rows: [{ text: "Text 1", checked: true, fields: "2", column: "X1" }] },
{ rows: [{ text: "Text 2", checked: true, fields: "2", column: "X1" }] },
{ rows: [{ text: "Text 3", checked: false, fields: "1", column: "X2" }] },
{ rows: [{ text: "Text 4", checked: false, fields: "2", column: "X2" }] },
{ rows: [{ text: "Text 5", checked: false, fields: "3", column: "X2" }] }
];
const result = {};
for(let a = 0, b = data.length; a < b; a++){
const item = data[a];
for(let c = 0, d = questions.length; c < d; c++){
const rows = questions[c].rows;
for(let e = 0, f = rows.length; e < f; e++){
const row = rows[e];
if(row.checked && item[row.column] === row.fields){
result[item.Name] = item;
break;
}
}
}
}
// this could be replaced with Object.values(result);
const matches = [];
for(let match in result){
matches.push(result[match]);
}
// not supported by IE yet
// Object.values(result);
console.log(matches);

Resources