data: [
{
cid: "211211",
parentCid: "212121",
level: 3,
number: "2.1.1",
subject: "Title 2.1.1"
},
{
cid: "111111",
parentCid: "",
lv: 1,
number: "1",
subject: "Title1"
},
{
cid: "222222",
parentCid: "",
lv: 1,
number: "2",
subject: "Title2"
},
{
cid: "212121",
parentCid: "222222",
lv: 2,
number: "2.1",
subject: "Title2.1"
},
{
cid: "333333",
parentCid: "",
lv: 1,
number: "3",
subject: "Title3"
}
]
I have a json data like above and I can get subject by data[i].subject.
For example, I can get "Title3" by data[i].subject.(i = 4)
then I can get "Title3" prev item by data[i-1].subject and I will get "Title2.1".
My questionis , is there any way that I can get prev item in same "lv"(level)?
in english is something like "data[ previtem in same lv] ?
Thanks and sorry for bad english.
I've seen your previous question yesterday... I suppose that if you need to do it (search for spec element by level) for many times, you should sort the array. Or you just need to do it for few times, you just need a loop to find the previous element you want.
A simple method like this:
function findPrev(i) {
var level = data[i--].lv;
while (i >= 0) {
if (data[i].lv === level) return i;
i--;
}
return -1; // not found
}
See the complete demo:
var data = [
{
cid: "211211",
parentCid: "212121",
lv: 3,
number: "2.1.1",
subject: "Title 2.1.1"
},
{
cid: "111111",
parentCid: "",
lv: 1,
number: "1",
subject: "Title1"
},
{
cid: "222222",
parentCid: "",
lv: 1,
number: "2",
subject: "Title2"
},
{
cid: "212121",
parentCid: "222222",
lv: 2,
number: "2.1",
subject: "Title2.1"
},
{
cid: "333333",
parentCid: "",
lv: 1,
number: "3",
subject: "Title3"
}
];
function findPrev(i) {
var level = data[i--].lv;
while (i >= 0) {
if (data[i].lv === level) return i;
i--;
}
return -1; // not found
}
console.log(data[findPrev(4)]); // data[4] go find data[2]
I'm assuming you already have an index i of the "current item", or know how to get it. In that case, a naive method would be to move backwards from the current item in a loop, comparing lv:
var previousItemIndex = i - 1;
while(previousItemIndex >= 0 && data[i].lv !== data[previousItemIndex].lv)
previousItemIndex--;
This will traverse the array backwards from i, finding the first element with a matching lv property, or returning -1 if it does not exist.
This also assumes that "previous" means in the same order as presented in the JSON array (i.e. the index has semantic meaning). If you meant to order by something else, for example number, you might consider sorting the entire thing first.
LateBloomer, The answer to your question is simple. To find the previous element with same level, all you need to do is decrement "i" and check whether the level is same or not. If not then decrement again.
Exactly what iplus26 did.
I think you want something like this:
function prevItemSameLv(data, i) {
for (var idx=i-1; idx>=0; idx--) {
if (data[idx].lv == data[i].lv) return data[idx];
}
}
You can use library like _lodash, it has function named "findIndex", read more here: https://lodash.com/docs#findIndex But it will return only one value.
Also, you can check this question, about filtering data: lodash Filter collection using array of values
Related
I am trying to filter an array of object (mainArr ) with dynamically updating object which has list of array (arrTofilter) which looks like bellow , I have 2 test inputs one of them is working as expected but the other one is failing.
let mainArr = [{
AREA: "INDIA",
GROUP_DESC: "Group A",
BUSINESS_ID: "1",
SUB_REGION: "KARNATAKA"
}, {
AREA: "INDIA",
GROUP_DESC: "Group A",
BUSINESS_ID: "2",
SUB_REGION: "Tamilnadu"
}, {
AREA: "INDIA",
GROUP_DESC: "Group C",
BUSINESS_ID: "3",
SUB_REGION: "Kerala"
}, {
AREA: "AFRICA",
GROUP_DESC: "Group D",
BUSINESS_ID: "4",
SUB_REGION: "Nigeria"
}];
//input 1 : input array
let arrTofilter = {
AREA: [],
GROUP_DESC: ['Group A', 'Group D'],
BUSINESS_ID: ['2'],
SUB_REGION: []
};
//so far tried code
const finalArr = mainArr.filter(({
GROUP_DESC,
BUSINESS_ID
}) => arrTofilter.GROUP_DESC.includes(GROUP_DESC) && arrTofilter.BUSINESS_ID.includes(BUSINESS_ID));
The above code works fine if the input array (arrTofilter) is like scenario 1,
in second scenario if the input array is like bellow then code fails , How can i make this work for both the inputs?
//input 2 : input array
let arrTofilter = {AREA: [], GROUP_DESC: ['Group A','Group D'], BUSINESS_ID: [], SUB_REGION: []};
Note: just removing my && statement will work but my input array is huge and even the main array so I can do && for multiple inputs but again if the user sends in single input this wont work
You should be able to check if for example arrTofilter.GROUP_DESC is empty or not (by checking the length of the array). If it's empty, then it should not be included as a filter. Do this for all four potential filters (AREA, GROUP_DESC, BUSINESS_ID and SUB_REGION).
const finalArr = mainArr.filter(({
AREA
GROUP_DESC,
BUSINESS_ID,
SUB_REGION
}) => (arrTofilter.AREA.length === 0 || arrTofilter.AREA.includes(AREA)) &&
(arrTofilter.GROUP_DESC.length === 0 || arrTofilter.GROUP_DESC.includes(GROUP_DESC)) &&
(arrTofilter.BUSINESS_ID.length === 0 || arrTofilter.BUSINESS_ID.includes(BUSINESS_ID)) &&
(arrTofilter.SUB_REGION.length === 0 || arrTofilter.SUB_REGION.includes(SUB_REGION));
I am having trouble effectively identifying/replacing the value I need inside an Object for an editing pay rates application.
{
Physicians: {
telehealth: {
orgName: "ORG B",
weekdayEncounters: { type: "each", value: 15 },
weeknightEncounters: { type: "each", value: 16.25 },
weekendDayEncounters: { type: "each", value: 16.25 },
weekendNightEncounters: { type: "each", value: 17.25 },
holidayEncounters: { type: "each", value: 17.25 },
stipend: { type: "lump", value: 0 },
},
},
NonPhysicians: {
telehealth: {
orgName: "ORG B",
weekdayEncounters: { type: "each", value: 15 },
weeknightEncounters: { type: "each", value: 16.25 },
weekendDayEncounters: { type: "each", value: 16.25 },
weekendNightEncounters: { type: "each", value: 17.25 },
holidayEncounters: { type: "each", value: 17.25 },
stipend: { type: "lump", value: 0 },
},
},
date: "07-2021",
orgName: "ORG B",
ltc: false,
}
I am looking to replace the value inside the deepest object depending on the field that is edited. At this point I just keep getting messier and messier code trying to dig into the object read it and then replace the correct value. I have an example in written up here. Please take it easy on me I am still learning. Advice would be greatly appreciated.My issue currenlty is that I am returning an array full of undefineds and then the one object I need. Thanks in advance.
I went into your example and took the top level object 'NEWRATES'. The example code below goes through each of the sub-object NEWRATES['ltc'][0]['Infinity']['Physicians']['associates'], and prints the value under the key 'value'. It also does a quick check for the type since the lowest level contains some keys that map to strings, e.g. (orgName: "Infinity").
The Object.entries function call is necessary to make the indicated object NEWRATES[...] iterable.
for( let [key,value] of Object.entries(NEWRATES["ltc"][0]['Infinity']['Physicians']['associates']) ){
if(typeof value == "object"){
console.log('value is: ' + value.value);
}
}
This should be enough to get you going again. Simply replace the top level keys from 'ltc' -> 'standard' , 'Physicians' -> 'NonPhysicians' to iterate through the other portions of the top level object.
a structure like this: // (id´s simplified)
User:
{_id : ObjectId("4"), name: "Max Sampleman"}
{_id : ObjectId("5"), name: "Jon Doe"}
Books:
{_id : ObjectId("1"), title: "MongoDB Overview", "likes": 3, contributor: ObjectId("5") }
{_id : ObjectId("2"), title: "NoSQL Overview", "likes": 2, contributor: ObjectId("4")}
{_id : ObjectId("3"), title: "Tutorials Point Overview", "likes": 6, contributor: ObjectId("5")}
Now I'm looking for a way to find the books, sort them by likes, but return the ones from user 4 first.
An approach like this doesn't seem to work:
user4 = await User.findById(4)
books.find({}).sort({contributor: user4.id, likes: -1})
It returns an error, saying:
"message": "Invalid sort value: { contributor: 4 }"
Is there a way to achieve that kind of sorting?
The values allowed for sort are asc, desc, ascending, descending, 1, and -1, so you will not be able to pass the id instead of these values.
One way to achieve your requirement would be with aggregate and $set, You can add a new field and set it to true for the particular id you need to get first and use that field in while sorting.
books.aggregate([
{ $set: { priority: { $eq: ["$contributor", user4.id] } } },
{ $sort: { priority: -1, likes: -1 } },
]);;
I am working on an offer letter template that will replace/modify Dynamic Data Points like Name, Address, Role, Salary, etc based on the candidate selected from a list of candidates. There is a fixed syntax for a dynamic data points i.e they will be enclosed within <<>>, for example :
Welcome to the family, <<Name>>
You will be paid <<Salary>> for the duration of your employment.
In other words, these few data points will change by selecting the candidate we want to offer the job and the rest of the template will remain the same. Here is a demo to help you understand.
This is a dummy array I have created with 1 template, In the real-world app, I can have many templates with different clauseNames, so I am looking for a permanent fix.
.ts file, Template List :
[{
templateId: 1,
templateName: "Offer",
clauses: [
{
clauseName: "Introduction",
clauseId: 1,
texts: [
{
text: "Hello <<Name>>, Welcome to the Machine",
textId: 1,
}]
},
{
clauseName: "Address",
clauseId: 2,
texts: [
{
text: "<<Address>>",
textId: 2,
}]
},
{
clauseName: "Date Of Joining",
clauseId: 3,
texts: [
{
text: "You can join us on <<DateOfJoining>>",
textId: 3,
}]
},
]
}]
and here is the candidate list,
candidateList = [
{ name: "Simba", address: "Some Random Cave" },
{ name: "Doe John", address: "line 4, binary avenue, Mobo" },
{ name: "B Rabbit", address: "8 mile road, Detroit" },
{ name: "Peter Griffin", address: "Spooner Street" },
{ name: "Speedy Gonzales", address: "401, hole 34, Slyvester Cat Road" },
{ name: "Morty", address: "Time Machine XYZ" },
{ name: "Brock", address: "pokeball 420, Medic center" },
]
You can use regular expressions to replace those placeholders such as:
var result = text.text.replace(/\<\<(.*?)\>\>/g, function(match, token) {
return candidate[token.toLowerCase()];
});
One way to incorporate this to your display is by creating a property that returns the formatted text.
I have updated your stackblitz here.
Take a look at this demo
I have modified the logic in below method:
showTeplate(name,address,doj) {
this.clauseList = [];
for (let a of this.templateList) {
if (a.clauses != null) {
for (let cl of a.clauses) {
const tempObj = JSON.parse(JSON.stringify(cl));
tempObj.texts.forEach(textObj => {
textObj.text = textObj.text.replace("<<Name>>",name);
textObj.text = textObj.text.replace("<<Address>>",address);
textObj.text = textObj.text.replace("<<DateOfJoining>>",doj);
})
this.clauseList.push(tempObj)
}
}
}
console.log("Clause list", this.clauseList)
}
I have a JSON array fetch from my server which looks like :
[ {name: "Web Design", id: "27", month_n: "1", data: "68.00"},
{name: "Web Design", id: "27", month_n: "2", data: "56.00"} ,
{name: "Homework", id: "4", month_n: "2", data: "15.00"} ,
{name: "Gaming", id: "12", month_n: "2", data: "5.00"} ]
On the client side, I want to reorder this to have something similar to :
[{name: "Web Design", data:[68.00,56.00]}, {name:"Homework", data:[0,15]} and so on...
Where the "data" value is grouped by the "id" number and the month number (by default 0 if there's no month that match).
What's the best way ? I tried it the pure JavaScript way but I'm getting a hard time ! I have also heard It is easier with underscore JS. But don't know where to start.
Will someone please enlighten me ?
This can be done by two operations:
Groupby [name] field, then
Pluck [data] fields
There are pure JS array prototype extensions libraries to achieve this and many other operations with couple of lines. You may take a look at underscore.js. I have also written a simple JS library jsList. It comes with many unit-tests to use as example.
You only need to write these lines:
var arr = [ {name: "Web Design", id: "27", month_n: "1", data: "68.00"},
{name: "Web Design", id: "27", month_n: "2", data: "56.00"} ,
{name: "Homework", id: "4", month_n: "2", data: "15.00"} ,
{name: "Gaming", id: "12", month_n: "2", data: "5.00"} ];
var temp = arr.groupBy(function(item){ return item.name });
var result = [];
for(var key in temp){
result.push({name: key, data: temp[key].pluck('data')});
}
You may use Object.keys to avoid the for loop, but it only comes with Javascript 1.8.5 or later.
Thanks.
One way to do this in vanilla JavaScript, is to use a helper object as in the following code.
In a first step, we identify all distinct name values and group all data field by them.
In the second step, the helper object is converted back to an array.
var arr = [ {name: "Web Design", id: "27", month_n: "1", data: "68.00"},
{name: "Web Design", id: "27", month_n: "2", data: "56.00"} ,
{name: "Homework", id: "4", month_n: "2", data: "15.00"} ,
{name: "Gaming", id: "12", month_n: "2", data: "5.00"} ];
// use a helper object to identify all distinct "names"
var helper = {};
for( var i=arr.length; i--; ) {
// init an array, if it is not there
helper[ arr[i]['name'] ] = helper[ arr[i]['name'] ] || [];
// add the newest element
helper[ arr[i]['name'] ].push( helper[ arr[i]['data'] ] );
}
// convert back to an array
var newArr = [];
for( var key in helper ) {
if( helper.hasOwnProperty( key ) ) {
newArr.push( { 'name': key, 'data': helper[key] } );
}
}