Can I please get some help with this scenario?
An array of strings
A function that maps the array of strings and applies to each one of them a name, key and adds one more object "checked: false".
A function that takes the mapped array and transforms it according to the argument passed, storing the value in to another array and changing the "checked" to value "true"
Ex:
const defaultProducts = [
"Laptop",
"Tablet",
"Phone",
"Ram",
"SSD",
"RasberyPi",
"Desktop",
"TV",
"Monitor"
];
const getDefaultProducts = () => {
return defaultProducts.map(products => {
return {
name: products,
checked: false
};
});
};
console.log(getDefaultProducts())
let forSale = []
function useProduct(product){
if(product in getDefaultProducts()) {
return{
product: forSale.push(product),
checked: true
};
};
return {product};
}
console.log(useProduct("Laptop"))
console.log(forSale)
returns
[ { name: 'Laptop', checked: false },
{ name: 'Tablet', checked: false },
{ name: 'Phone', checked: false },
{ name: 'Ram', checked: false },
{ name: 'SSD', checked: false },
{ name: 'RasberyPi', checked: false },
{ name: 'Desktop', checked: false },
{ name: 'TV', checked: false },
{ name: 'Monitor', checked: false } ]
{ product: 'Laptop' }
[]
Should return:
[ { name: 'Laptop', checked: false },
{ name: 'Tablet', checked: false },
{ name: 'Phone', checked: false },
{ name: 'Ram', checked: false },
{ name: 'SSD', checked: false },
{ name: 'RasberyPi', checked: false },
{ name: 'Desktop', checked: false },
{ name: 'TV', checked: false },
{ name: 'Monitor', checked: false } ]
{ product: 'Laptop' }
[{name:"Laptop", checked: true}]
In the part where you checked the condition as if product in getDefaultProducts () will not work since getDefaultProducts is an array of objects. You are comparing strings with each object such as:
"Laptop" === { name: "Laptop", checked: false }
which will return false always. Instead you can use find function:
function useProduct(product){
getDefaultProducts().find(el => {
if (el.name === product) {
el.checked = true
forSale.push(el)
}
});
return product;
}
Try with this:
function useProduct(product){
const found = getDefaultProducts().find(p => p.name === product)
if (found) {
found.checked = true
forSale.push(found)
}
return {product}
}
Related
I have data array, which has nested arrays inside (level1arr, leve21arr ...)
const data = [
{
level1arr: [
{
level2arr: [{ id: 1, isValid: true }, { id: 2, isValid: true }, { id: 3, isValid: true }],
},
{
level2arr: [{ id: 4, isValid: true }, { id: 5, isValid: true }, { id: 6, isValid: true }],
},
],
},
{
level1arr: [
{
level2arr: [{ id: 7, isValid: true }, { id: 8, isValid: true }, { id: 9, isValid: true }],
},
{
level2arr: [{ id: 10, isValid: true }, { id: 11, isValid: true }, { id: 12, isValid: true }],
},
],
},
];
I also have another array:
const invalidIds = [2,5]
I want to find elements with apecyfic id and change isValid property to false.
Is it better way than iteratinf over multiple nested arrays, like that:
data.forEach(lvl1 => {
lvl1.level1arr.forEach(lvl2 => {
lvl2.level2arr.forEach(element => {
// further nesting
});
});
})
Such iterating over multiple arrays is not good for performance. What is the best way to handle such case with nested arrays?
If it were nested arrays, you could use Array.prototype.flat(). However, you have a mix of nested objects and arrays. You will have to write a custom "flattener" for this data structure. Check this answer for details: how to convert this nested object into a flat object?
You can use recursion until you reach the level you need. Here's one way to do it.
const data = [{
level1arr: [{
level2arr: [{
id: 1,
isValid: true
}, {
id: 2,
isValid: true
}, {
id: 3,
isValid: true
}],
},
{
level2arr: [{
id: 4,
isValid: true
}, {
id: 5,
isValid: true
}, {
id: 6,
isValid: true
}],
},
],
},
{
level1arr: [{
level2arr: [{
id: 7,
isValid: true
}, {
id: 8,
isValid: true
}, {
id: 9,
isValid: true
}],
},
{
level2arr: [{
id: 10,
isValid: true
}, {
id: 11,
isValid: true
}, {
id: 12,
isValid: true
}],
},
],
},
];
const invalidIds =[2,5]
const findId = (object, key, value) => {
if (Array.isArray(object)) {
for (const obj of object) {
findId(obj, key, value);
}
} else {
if (object.hasOwnProperty(key) && object[key] === value) {
object.isValid = false;
return object
}
for (const k of Object.keys(object)) {
if (typeof object[k] === "object") {
findId(object[k], key, value);
}
}
}
}
invalidIds.forEach(id => findId(data, "id", id))
console.log(data)
This question already has an answer here:
How does React useState hook work with mutable objects
(1 answer)
Closed 2 years ago.
const [bullyTypes, setBullyTypes] = React.useState([
{ value: "Exotic", isChecked: false },
{ value: "Pocket", isChecked: false },
{ value: "Classic", isChecked: false },
{ value: "Standard", isChecked: false },
{ value: "Extreme", isChecked: false },
{ value: "XL", isChecked: false },
]);
const handleBullyTypeChange = (event) => {
let bullyTypesCopy = bullyTypes;
bullyTypesCopy.forEach((bullyTypeCopy) => {
if (bullyTypeCopy.value === event.target.value) {
bullyTypeCopy.isChecked = event.target.checked;
}
});
setBullyTypes(bullyTypesCopy); // not working
setBullyTypes([
{ value: "Exotic", isChecked: true },
{ value: "Pocket", isChecked: false },
{ value: "Classic", isChecked: false },
{ value: "Standard", isChecked: false },
{ value: "Extreme", isChecked: false },
{ value: "XL", isChecked: false },
]); // this is working even though bullyTypesCopy variable has the same value with this array of objects.
};
When I pass the exact array as argument to setBullyTypes it works
but when i pass the variable containing the array it wont work even though they have the same value
Please help me. Thanks
In the event handler bullyTypesCopy is copied by reference, and forEach is not doing what you expect, it just iterate over the array entries. I think what you need to do is use map in order to actually get a new content based on your condition. In this way setBullyTypes should work.
Please try the following example
const [bullyTypes, setBullyTypes] = React.useState([
{ value: "Exotic", isChecked: false },
{ value: "Pocket", isChecked: false },
{ value: "Classic", isChecked: false },
{ value: "Standard", isChecked: false },
{ value: "Extreme", isChecked: false },
{ value: "XL", isChecked: false },
]);
const handleBullyTypeChange = (event) => {
let bullyTypesCopy = bullyTypes.map((bullyTypeCopy) => {
if (bullyTypeCopy.value === event.target.value) {
return { ...bullyTypeCopy, isChecked: !event.target.checked };
}
return { ...bullyTypeCopy };
});
setBullyTypes(bullyTypesCopy); // not working // this should work now
setBullyTypes([
{ value: "Exotic", isChecked: true },
{ value: "Pocket", isChecked: false },
{ value: "Classic", isChecked: false },
{ value: "Standard", isChecked: false },
{ value: "Extreme", isChecked: false },
{ value: "XL", isChecked: false },
]); // this is working even though bullyTypesCopy variable has the same value with this array of objects.
};
I have mongoDB companies collection
c00:
{
_id: c00,
name: 'acme',
results: [
0: { _id: 'a10', name: 'foo', visible: true },
1: { _id: 'a11', name: 'bar', visible: false }
],
},
c01:
{
_id: c01,
name: 'apra'
results: [
0: { _id: 'b10', name: 'foo', visible: false },
1: { _id: 'b11', name: 'bar', visible: true },
2: { _id: 'b12', name: 'qux', visible: true },
]
}
}
I need query that modify
company.c01.results with resultId === 'b11'`
to
{ _id: 'b11', name: 'bar', visible: false }
I have tried
CompanyModel
.update(
{ [`${companyId}.results`]: resultsId },
{
$set: { ['results.$.visible']: false },
}
)
but this didn't work.
Any help will be appreciated
You need to put the dynamic key at the time of $set as well
CompanyModel.update(
{ [`${companyId}.results._id`]: resultsId },
{ $set: { [`${companyId}.results.$.visible`]: false }}
)
Try
CompanyModel.update(
{ "company.c01.sets._id": "b11" },
{ "$set": { "company.$.c01.visible": false } }
)
I'm trying to build a JS function to convert the data structure in the form of
'start' to the form of 'expected'.
Using JS map() method, how would I do this for the following associative array-
const start = {
Clients: {
171: { id: 171, name: 'John Smith', active: false },
172: { id: 172, name: 'Jacob Jacobson', active: true },
1441: { id: 1441, name: 'Eric Ericsson', active: true },
},
Caregivers: {
1: { id: 1, name: 'John Johnson', active: true },
37: { id: 37, name: 'James Jameson', active: false },
15: { id: 15, name: 'Aaron Aaronson', active: true },
},
Doctors: {
1147: { id: 1147, name: 'Doc Docson', active: true },
},
Hospitals: {
115: { id: 115, active: false, name: "St. Mary's" },
},
Applicants: {
17345: { id: 17345, name: 'Bob Bobson', active: true },
17346: { id: 17346, name: 'Jeff Jeffson', active: false },
17347: { id: 17347, name: 'Frank Frankson', active: true },
17348: { id: 17348, name: 'Bill Billson', active: true },
},
};
needs to be converted to-
const expected = [
{ label: 'Bill Billson', value: 17348, group: 'Applicants' },
{ label: 'Bob Bobson', value: 17345, group: 'Applicants' },
{ label: 'Frank Frankson', value: 17347, group: 'Applicants' },
{ label: 'Aaron Aaronson', value: 15, group: 'Caregivers' },
{ label: 'John Johnson', value: 1, group: 'Caregivers' },
{ label: 'Eric Ericsson', value: 1441, group: 'Clients' },
{ label: 'Jacob Jacobson', value: 172, group: 'Clients' },
{ label: 'Doc Docson', value: 1147, group: 'Doctors' },
];
.map() can't be used directly on Objects; instead you'll need to use Object.keys
const start = {
Clients: {
171: { id: 171, name: 'John Smith', active: false },
172: { id: 172, name: 'Jacob Jacobson', active: true },
1441: { id: 1441, name: 'Eric Ericsson', active: true }
},
Caregivers: {
1: { id: 1, name: 'John Johnson', active: true },
37: { id: 37, name: 'James Jameson', active: false },
15: { id: 15, name: 'Aaron Aaronson', active: true }
},
Doctors: {
1147: { id: 1147, name: 'Doc Docson', active: true }
},
Hospitals: {
115: { id: 115, active: false, name: "St. Mary's" }
},
Applicants: {
17345: { id: 17345, name: 'Bob Bobson', active: true },
17346: { id: 17346, name: 'Jeff Jeffson', active: false },
17347: { id: 17347, name: 'Frank Frankson', active: true },
17348: { id: 17348, name: 'Bill Billson', active: true }
}
};
// Get an array of properties in 'start'
// then use Array.reduce() to loop over each item
const expected = Object.keys(start).reduce( (res, gKey) => {
// gKey = 'group' name
// gVal = 'group' value
let gVal = start[gKey];
// loop over each item in the 'group'
Object.keys(gVal).forEach(iKey => {
// iKey = 'group.item' name
// iVal = 'group.item' value
let iVal = gVal[iKey];
// if the value's .active property is truthy
if (iVal.active) {
// format the result as desired and add it to the result array
res.push({
label: iVal.name,
value: iKey,
group: gKey
});
}
});
// return the result array
return res;
// start the .reduce() with an empty array
}, []);
console.log(expected);
To loop over an object, you can either use a for ... in loop, or use Object.keys to get an array of keys. For ... in will include inherited properties, so you may need to manually filter them out. Object.keys only returns own properties, so there's no need to do the filtering (but it also isn't appropriate if you need inherited properties)
Example with for ... in:
for (var prop in start) {
if (start.hasOwnProperty(prop)) {
// logs out 'Clients', then 'Caregivers', then 'Doctors', then 'Hospitals', then 'Applicants'
console.log(prop);
}
}
Example with Object.keys:
//produces array ['Clients', 'Caregivers', 'Doctors', 'Hospitals', 'Applicants']
var keys = Object.keys(start);
So if you wanted to use .map, you can start with this, and fill it in to do whatever you desire:
Object.keys(start)
.map(key => {
//do something with start[key]
//perhaps you could get Object.keys(start[key]) and loop over that as well.
});
My solution without 'forEach':
function transform(data) {
Object.entries(data).map(item => Object.values(item[1])
.map(i => i.group = item[0]))
.reduce(( acc, cur ) => acc.concat(cur), [])
.filter(item => item.active === true)
.sort((a, b) => a.group - b.group)
.map(item => {
let expected = {};
expected.label = item.name;
expected.value = item.id;
expected.group = item.group;
});
return expected;
}
I wrote a function that when given a list of objects and an
id, returns the same list, but with the corresponding object marked active
(all other objects should not be active).
const list = [
{ id: 1, active: false },
{ id: 2, active: false },
{ id: 3, active: true },
{ id: 4, active: false }
];
function markActive(list, value) {
list.forEach((id) => {
if (id.active = (id.id === value)) {
return true;
} else {
return false;
}
});
}
markActive(list, 2);
console.log(list)
Returns:
[ { id: 1, active: false },
{ id: 2, active: false },
{ id: 3, active: false },
{ id: 4, active: true } ]
It's working like a charm, except when I run "npm run [filename]" I get an error message:
Running Tests for [filename].
------------
[ { id: 1, active: false },
{ id: 2, active: false },
{ id: 3, active: false },
{ id: 4, active: true } ]
markActive
1) Case 1 (Given Sample)
2) Case 2 (String IDs)
0 passing (16ms)
2 failing
1) markActive Case 1 (Given Sample):
AssertionError: expected undefined to deeply equal [ { id: 1,
active: false },
{ id: 2, active: true },
{ id: 3, active: false },
{ id: 4, active: false } ]
at Function.assert.deepEqual
(node_modules/chai/lib/chai/interface/assert.js:216:32)
at Context.it (tests/test_02.js:23:12)
2) markActive Case 2 (String IDs):
AssertionError: expected undefined to deeply equal [ { id: '1',
active: false },
{ id: '2', active: true },
{ id: '3', active: false },
{ id: '4', active: false } ]
at Function.assert.deepEqual
(node_modules/chai/lib/chai/interface/assert.js:216:32)
at Context.it (tests/test_02.js:40:12)
Any idea what I'm doing wrong? Here's the code that sets up the tests:
const chai = require("chai");
const sinon = require("sinon");
const assert = chai.assert;
const markActive = require("../answers/02.js");
describe("markActive", () => {
it("Case 1 (Given Sample)", () => {
var list = [
{ id: 1, active: false },
{ id: 2, active: false },
{ id: 3, active: true },
{ id: 4, active: false }
];
var newList = markActive(list, 2);
var targetList = [
{ id: 1, active: false },
{ id: 2, active: true },
{ id: 3, active: false },
{ id: 4, active: false }
];
assert.deepEqual(newList, targetList);
});
it("Case 2 (String IDs)", () => {
var list = [
{ id: "1", active: false },
{ id: "2", active: false },
{ id: "3", active: true },
{ id: "4", active: false }
];
var newList = markActive(list, "2");
var targetList = [
{ id: "1", active: false },
{ id: "2", active: true },
{ id: "3", active: false },
{ id: "4", active: false }
];
assert.deepEqual(newList, targetList);
});
});
Your function isn't returning anything, so any variables you try to set to the result will be set as undefined.
To fix this, simply add a return statement to the end of your function.
function markActive(list, value) {
list.forEach((id) => {
if (id.active = (id.id === value)) {
return true;
} else {
return false;
}
});
return list; // return the updated list
}
NOTE: It's worth mentioning that because the array is referenced, you're modifying the values in-place. This is why the array you defined outside the function still had updated results even though you weren't logging the returned value. This can have unintended side effects if you were to run the markActive() function several times on the same list. If you want a new list to be returned, look into ways of copying and deep copying arrays in Javascript.