Related
I am wondering what js functions can be used in the following case to get some array values together.
Here I want to concatenate the description values if the date value is null.
var incomes = [ { date: '05/03', description: '1st Description on 05/03', amount: '399.49' },
{ date: null, description: '1st Description continued on 05/03', amount: null },
{ date: null, description: '1st Description continued on 05/03', amount: null },
{ date: '05/03', description: '2nd Description on 05/03', amount: '269.85' },
{ date: null, description: '2nd Description continued on 05/03', amount: null },
{ date: null, description: '2nd Description continued on 05/03', amount: null }];
The result should look like this:
var results = [ { date: '05/03',
description: '1st Description on 05/03, 1st Description continued on 05/03, 1st Description continued on 05/03',
amount: '399.49' },
{ date: '05/03',
description: '2nd Description on 05/03, 2nd Description continued on 05/03, 2nd Description continued on 05/03',
amount: '269.85' }];
I think that we can use the usual loops, conditions, etc. But are there any handy method to solve this?
This really isn't a good use case for reduce/concat types of operations. Reduce is supposed to be given a pure function that only relies on its parameters and doesn't mutate any values. You're trying to produce an array, which would either involve creating the array and then mutating it (adding values), or creating copies of the array (via concat), like this:
const results = incomes.reduce((agg, v) =>
v.date
? agg.concat([v])
: agg.slice(0, -1)
.concat([{
...agg.slice(-1)[0],
description: `${agg.slice(-1)[0].description}, ${v.description}`}]),
[])
As you can see, there's a lot of duplicative sliceing and concating going on here, which is wasteful from a performance perspective. Perhaps more importantly, it's hard to reason with and hard to debug. I'd probably stick with using a for loop that tracks state and pushes to an array instead.
let results = [];
for (let v of incomes) {
if (v.date) {
results.push({...v});
} else {
results[results.length - 1].description += ", " + v.description;
}
}
I'm using Node (https://eemeli.org/yaml/) to parse a YAML configuration files which looks like so:
items:
- name: item 1
value: 25
- name: item 2
value: 25
- name: item 3
value: 50
What I'd like to do is assert the value numbers all add up to 100 when parsing the document.
Should I be running this validation after parsing the YAML
eg:
data = YAML.parse(recipe)
validate(data)
Or is there a better way of doing this using the YAML library directly when loading the document?
Thanks in advance for your help!
You're better of parsing the YAML first, then going through the resulting data. So, in this case, the parsed data would look something like:
data = {
items: [
{name: 'item 1', value: 25},
{name: 'item 2', value: 25},
...
]
}
So, you can just loop through the values:
let total = 0;
data.items.map((item) => {
total += item.value;
});
if (total !== 100) {
...
}
I have an issue with manipulating data in Javascript/jQuery and I could use some help.
I have an array of objects that lools like this:
var projects = [
{title:'project1'},
{title:'project2'},
{title:'project3'},
];
I have another array of objects that looks like this:
ganttEvents = [
{
text: 'some text',
start_date: '2018/06/13',
end_date: '2018/06/14',
id: '1',
readonly: true,
project: 'project1',
category: 'scoping',
}
{
text: 'some text2',
start_date: '2018/06/14',
end_date: '2018/06/15',
id: '1',
readonly: true,
project: 'project2',
category: 'scoping',
}
{
text: 'some text3',
start_date: '2018/06/15',
end_date: '2018/06/16',
id: '1',
readonly: true,
project: 'project2',
category: 'design',
}
{
text: 'some text4',
start_date: '2018/06/13',
end_date: '2018/06/14',
id: '1',
readonly: true,
project: 'project2',
category: 'scoping',
}
{
text: 'some text5',
start_date: '2018/06/14',
end_date: '2018/06/15',
id: '1',
readonly: true,
project: 'project3',
category: 'testing',
}
{
text: 'some text6',
start_date: '2018/06/15',
end_date: '2018/06/16',
id: '1',
readonly: true,
project: 'project3',
category: 'build',
}
];
The project field in the second object will always be one of the objects in the first array.
I then need to end up with an object that looks like this:
source: [
{
name: "project1", // a project defined in the projects array
desc: "scoping", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/13", // the start_date from the ganttEvents array of objects
from: "2018/06/14", // the end_date from the ganttEvents array of objects
desc: "some text", // the text from the ganttEvents array of objects
label: "some text", // the text from the ganttEvents array of objects
}
]
},
{
name: "project2", // a project defined in the projects array
desc: "scoping", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/14",
from: "2018/06/15",
desc: "some text2",
label: "some text2",
},
{
to: "2018/06/13",
from: "2018/06/14",
desc: "some text4",
label: "some text4",
},
]
},
{
name: "project3", // a project defined in the projects array
desc: "testing", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/14",
from: "2018/06/15",
desc: "some text5",
label: "some text5",
}
]
},
{
name: "project3", // a project defined in the projects array
desc: "build", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/15",
from: "2018/06/16",
desc: "some text6",
label: "some text6",
}
]
},
]
There may be several values at all stages for each project and there maybe projects with no events at all that need to be omitted from the source object.
Please can you assist?
Edit:
The background behind this is that I am pulling a list of events from a SharePoint list using SharePointPlus. This results in the ganttEvents array. I need to plug this in to the jQuery.Gantt library which requires the events to be formatted in a particular way.
jQuery.Gantt
I am sorry but i am relatively new to Javascript (Python programmer usually) I have tried different methods of doing this to no avail.
You can use reduce to group the array into an object. Use the concatenated values of project and category as the key. Use Object.values to convert the object into an array.
var ganttEvents = [{"text":"some text","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project1","category":"scoping"},{"text":"some text2","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text3","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project2","category":"design"},{"text":"some text4","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text5","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project3","category":"testing"},{"text":"some text6","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project3","category":"build"}];
var result = Object.values(ganttEvents.reduce((c, v) => {
let k = v.project + "-" + v.category;
c[k] = c[k] || {name: v.project,desc: v.category,values: []};
c[k].values.push({to: v.end_date,from: v.start_date,desc: v.text,label: v.text});
return c;
}, {}));
console.log(result);
Without Object.values(), you can loop using for
var ganttEvents = [{"text":"some text","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project1","category":"scoping"},{"text":"some text2","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text3","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project2","category":"design"},{"text":"some text4","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text5","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project3","category":"testing"},{"text":"some text6","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project3","category":"build"}];
var temp = ganttEvents.reduce((c, v) => {
let k = v.project + "-" + v.category;
c[k] = c[k] || {name: v.project,desc: v.category,values: []};
c[k].values.push({to: v.end_date,from: v.start_date,desc: v.text,label: v.text});
return c;
}, {});
var result = [];
for (var key in temp) result.push(temp[key]);
console.log(result);
I have an array and I'm not sure how to access certain keys. What I'm trying to accomplish is simply target certain keys/values in the array. Here's a sample of my array.
var jobs = [
{
// hunting
name: 'Hunting',
available: [
{
name: 'Housemate',
description: 'You stick around the cabin of the hunters. You are the lowest class of the hunters.',
salary: 10
},
{
name: 'Fetcher',
description: 'You are the fetcher of the clan. You gather leather, resources, and skin leather.',
salary: 15
},
{
name: 'Hunter',
description: 'You are a basic hunter of the clan. You hunt for food, meat, and leather.',
salary: 25
},
{
name: 'Elder',
description: 'You are a elder of the clan. You are respected among many, and may ask hunters for arrons.',
salary: 0
}
],
// construction
name: 'Construction',
available: [
{
name: 'Builder',
description: 'You are a builder. You are the lowest class of the construction tier.',
salary: 45
},
{
name: 'Driver',
description: 'You are a driver. You do the fetching and gathering of resources.',
salary: 55
},
{
name: 'Engineer',
description: 'You are a engineer. You do the wiring and electrical work in the construction.',
salary: 65
},
{
name: 'Overseer',
description: 'You are the overseer. You watch over the construction and give orders.',
salary: 80
}
],
}
];
Now keep in mind that I have multiple arrays in one array. Here I try to access the Hunter job category, the Fetcher job, and the construction Engineer salary.
alert(jobs.'Hunting'); // gives 'missing name after . operator' error
alert(jobs.name[0]); // gives 'name is not defined' error
alert(jobs.available.'Fetcher'); //same error as number 1
alert(jobs.available.salary[0]) // gives available is not defined error
How can I access those variables?
Your array of objects is malformed
Your original array contained a single item: one object which had the name and available properties defined twice.
I suspect you want your array to contain two items: two objects, each with a name and available property.
It should be this:
var jobs = [
{
// hunting
name: 'Hunting',
available: [
{
name: 'Housemate',
description: 'You stick around the cabin of the hunters. You are the lowest class of the hunters.',
salary: 10
}, {
name: 'Fetcher',
description: 'You are the fetcher of the clan. You gather leather, resources, and skin leather.',
salary: 15
}, {
name: 'Hunter',
description: 'You are a basic hunter of the clan. You hunt for food, meat, and leather.',
salary: 25
}, {
name: 'Elder',
description: 'You are a elder of the clan. You are respected among many, and may ask hunters for arrons.',
salary: 0
}
]
}, {
// construction
name: 'Construction',
available: [
{
name: 'Builder',
description: 'You are a builder. You are the lowest class of the construction tier.',
salary: 45
}, {
name: 'Driver',
description: 'You are a driver. You do the fetching and gathering of resources.',
salary: 55
}, {
name: 'Engineer',
description: 'You are a engineer. You do the wiring and electrical work in the construction.',
salary: 65
}, {
name: 'Overseer',
description: 'You are the overseer. You watch over the construction and give orders.',
salary: 80
}
],
}
];
Accessing items in the array
alert(jobs[0].name); // Returns 'Hunting'
alert(jobs[0].available[1].name); // Returns 'Fetcher'
alert(jobs[0].available[3].salary); // Returns '0'
Why don't the following examples work?
You can't use a string in dot notation:
alert(jobs.'Hunting');
alert(jobs.available.'Fetcher');
You cannot have a string after the dot. You should have a property name as in object.name, but you first need to define by its index which item in the array you're targeting as in array[i].name.
But even if you changed it to…
alert(jobs[0].Hunting); // OR
alert(jobs[0]['Hunting']);
…it would fail because there is no object with a property name of 'Hunting'.
Square brackets are misplaced:
alert(jobs.name[0]);
alert(jobs.available.salary[0]);
The above examples don't work because you are passing an index inside square brackets after your property name, where they should be placed after the array name. For example:
alert(jobs[0].name);
alert(jobs[0].available[0].salary);
Accessing objects in array by key/value
It looks like you're attempting to access the object's in the array by the value from one of its properties.
For example, above it seems you want to get the object whose property of name has a value of 'Hunting', which cannot be done directly.
You would need to create a function or use a library that provides a function for this, such as Underscore's _.find.
Example of using _.find to get an object by key/value:
var hunting = _.find(jobs, function(obj) {
return obj.name === 'Hunting';
});
View the above examples in JSFiddle
I took the liberty of fixing a syntax error in you example. As you can see in the comments, there were close/opening braces missing between Hunter and Construction.
}]},
// construction
{name: 'Construction',
You will need to use the index notation to get at the different elements in the array.
This will return the Hunter object. From there you can access the individual elements (either name or available).
console.log(jobs[0]);
This will give you the name of the first object's name property.
console.log(jobs[0].name);
This will return the first object under available.
console.log(jobs[0].available[0]);
This will return the name property from the first object under available.
console.log(jobs[0].available[0].name);
Here is a fiddle I created
You didn't build your object correctly, do this :
var jobs = {
// New child object create only for Hunting
hunting: {
// hunting
name: 'Hunting', // optional
available: [
{
name: 'Housemate',
description: 'You stick around the cabin of the hunters. You are the lowest class of the hunters.',
salary: 10
},
{
name: 'Fetcher',
description: 'You are the fetcher of the clan. You gather leather, resources, and skin leather.',
salary: 15
},
{
name: 'Hunter',
description: 'You are a basic hunter of the clan. You hunt for food, meat, and leather.',
salary: 25
},
{
name: 'Elder',
description: 'You are a elder of the clan. You are respected among many, and may ask hunters for arrons.',
salary: 0
}
]
},
// Other section, this time for Construction
construction : {
// construction
name: 'Construction', // Optional too
available: [
{
name: 'Builder',
description: 'You are a builder. You are the lowest class of the construction tier.',
salary: 45
},
{
name: 'Driver',
description: 'You are a driver. You do the fetching and gathering of resources.',
salary: 55
},
{
name: 'Engineer',
description: 'You are a engineer. You do the wiring and electrical work in the construction.',
salary: 65
},
{
name: 'Overseer',
description: 'You are the overseer. You watch over the construction and give orders.',
salary: 80
}
],
}
};
Now you can do :
var construction_jobs = jobs.construction.available;
If you absolutely want keep your array on first dimention you can do it :
var jobs = [
{
// hunting
name: 'Hunting',
available: [ /* objects... */ ]
},
{
// construction
name: 'Construction',
available: [ /* objects... */ ]
}
];
And use lodash lib to get data :
var job = _.findWhere(jobs, {name: 'Hunting'});
To understand, check your console log display on this codepen : http://codepen.io/ArthyFiciel/pen/waGxrm
I'm passing some JSON data to a Jade template, but can't seem to print the JSON data to my Jade template. This is an example of the JSON which is stored and passed to the Jade template:
{ name: 'Team 1',
_id: 5134d71192cf972226000003,
__v: 0,
key: 1362417425623 }
It is passed through to the Jade template like so:
res.render('tournamentDetails', { 'tournamentData' : tournamentData, seedsSerialized : JSON.stringify(tournamentData.teams) } );
The format of the Jade template is:
script(type='text/javascript')
var seeds = [#{tournamentData.teams}];
I'm trying to access this variable seeds in a seperate JavaScript file, but cannot seem to access them. I have been testing using alert to test what is in seeds in the JavaScript file and it is not the teams.
This is the generated HTML from the Jade too:
var seeds = [{ name: 'Team 1',
_id: 5134d71192cf972226000003,
__v: 0,
key: 1362417425623 },{ name: 'Team 2',
_id: 5139dc66b48da58d0e000001,
__v: 0,
key: 1362746470498 },{ name: 'Team 3',
_id: 5139dda45f1598440f000001,
__v: 0,
key: 1362746788314 },{ name: 'Team 4',
_id: 513b2c66cfd50dce11000001,
__v: 0,
key: 1362832486554 }];
How would I access the teams in a JavaScript file? I am wanting to output the names of the teams to the Jade template.
This may not be an answer exactly, but it was too long for a comment...
Look at this jsfiddle: http://jsfiddle.net/KvXTA/
var seeds = [{ name: 'Team 1',
_id: 5134d71192cf972226000003,
__v: 0,
key: 1362417425623 },{ name: 'Team 2',
_id: 5139dc66b48da58d0e000001,
__v: 0,
key: 1362746470498 },{ name: 'Team 3',
_id: 5139dda45f1598440f000001,
__v: 0,
key: 1362746788314 },{ name: 'Team 4',
_id: 513b2c66cfd50dce11000001,
__v: 0,
key: 1362832486554 }];
console.log(seeds);
notice how the console outputs
Uncaught SyntaxError: Unexpected token ILLEGAL
That's because of the _id fields. I'm surprised you say that the serialized version has the same problem, since it should have surrounded the ID's in quotes. If you don't need the ID's at all, you can get rid of them in the serialized version by using a replacer function.
var seedsSerialized = JSON.stringify(teams, function (key, val) {
return key === '_id' ? undefined : val;
);
res.render('tournamentDetails', { seedsSerialized: seedsSerialized });
Then use that serialized version to initialize seeds in the template.
script
var seeds = !{seedsSerialized};
My earlier comment about order of including scripts wasn't a concern that maybe another file was creating a seeds variable, it was that you might have been including a file which used seeds before seeds was actually declared.
For example:
<script src='logSeeds.js'></script>
<script>
var seeds = [ ... ];
</script>
where logSeeds.js is:
console.log(seeds);
would obviously output undefined since seeds hasn't been declared yet. It was just a thought, not necessarily your situation.