I have an array that contains objects, like this:
"exams": [
{
"id": "62b30836e941368db5d0e531",
"name": "Basic",
"price": 100
},
{
"id": "62b30836e941368db5d0e532",
"name": "Full",
"price": 200
}
]
I need pick only the name property from every object, and build a string, where the elements are "separated" with comma.
Like this:
"Basic,Full"
I tried the following, but the method built every whole object into the string:
var e = exams.join(",");
Before using the .join() to create a string, you should map the values you want from the array of objects. Like this:
exams.map(exam => exam.name)
This should return something like: ['Basic', 'Full'].
Then you do the join.
You could do all in one line (also avoid var, use const instead):
const e = exams.map(exam => exam.name).join(',')
Related
I have a CSV of results that looks at a picture and makes a guess at whether or not a picture contains a certain attribute. In this case if the subject in the picture is male or female.
I'm converting this CSV to JSON with javascript/node and I want to take the attributes and their values and put them in an array inside of one object per pciture. Right now each line of the CSV measures and attribute but it means at least two lines per image.
Simple version of the csv:
path, detect_id, score, x-coord, y-coord, w-coord, h-coord, attribute, value
picture_1.jpg,0,1.44855535,74,54,181,181,genderf,0.024716798
picture_1.jpg,0,1.44855535,74,54,181,181,genderm,0.975283206
I can convert this CSV to JSON and then at least group items together by their path/filename.
But that leaves a lot of redundant information out there and I want to put my Attributes and their Value together in a nested object inside of the main one.
Like:
Path: picture_1.jpg
Attributes: [genderf: 0.025,
genderm: 0.985]
other_info: other info
Right now I'm using lodash to create the objects as you see below but if I try to map through the attributes I end up pushing out every element except the last one.
So I can create the object with the following code.
var result =
_([...arr1, ...arr2])
.concat()
.groupBy("path")
.value();
Where arr1 and arr2 is the data from one line of the output csv. All the information is the same except the attribute and its value.
That gets me this object:
{
"picture_1.jpg": [
{
"path": "picture_1.jpg",
"detect_id,": "0",
"score,": "1.44855535",
"coordinates": [
{
"x,": "74",
"y,": "54",
"w": "181",
"h": "181"
}
],
"attribute": "genderf",
"value": "0.024716798"
},
{
"path": "picture_1.jpg",
"detect_id,": "0",
"score,": "1.44855535",
"coordinates": [
{
"x,": "74",
"y,": "54",
"w": "181",
"h": "181"
}
],
"attribute": "genderm",
"value": "0.975283206"
}
]
}
Which at least groups pictures together based on the path heading but a lot of the information is redundant and this is just measuring one attribute.
You could just iterate all csv-lines and build an object/map while keeping track of already found file-names/paths. If you encounter a line whose path already exists in the map, just append the attribute/value pair. Something like this (note that I've changed the coords delimiter for the sake of simplicity and that it needs proper error handling):
const data = ["picture_1.jpg,0,1.44855535,74;54;181;181,genderf,0.024716798", "picture_1.jpg,0,1.44855535,74;54;181;181,genderm,0.975283206"];
function createImageDataMap(dataArr) {
const imageDataResult = {};
for (const imgData of dataArr) {
const currData = parseImgDataLine(imgData);
if (!imageDataResult[currData.path]) {
imageDataResult[currData.path] = {
attributes: [], other_info: {
score: currData.score,
detectId: currData.detectId,
coords: currData.coords
}
}
}
imageDataResult[currData.path].attributes.push({[currData.attribute]: currData.value});
}
return imageDataResult;
}
function parseImgDataLine(line) {
const attributes = line.split(',');
return {
path: attributes[0],
detectId: attributes[1],
score: attributes[2],
coords: attributes[3],
attribute: attributes[4],
value: attributes[5]
}
}
console.log(JSON.stringify(createImageDataMap(data)));
// prints {"picture_1.jpg":{"attributes":[{"genderf":"0.024716798"},{"genderm":"0.975283206"}],"other_info":{"score":"1.44855535","detectId":"0","coords":"74;54;181;181"}}}
I have a json file businessList.json with the following
[
{"availableTimes": [{"type": "time", "time": "06:30"}, {"type": "time", "time": "07:00"}]},
{"availableTimes": [{"type": "time", "time": "08:30"}, {"type": "time", "time": "07:00"}]}
]
In another file, I am trying to create a set out of this, but it won't work, it'll show all of the duplicate values. I'm assuming it's because of how objects are passed by reference. How could I solve this to get to the desired result?
const timesAvailable = new Set()
businessList.map(item => item.availableTimes.map(item => timesAvailable.add(item))) //won't work
Like the first comment by Pointy says, objects are only equal to each other in JavaScript if they refer to the same place in memory. For example,
const object1 = { foo: 'bar' };
const object2 = object1;
object1 === object2 //true;
{ foo: 'bar' } === { foo: 'bar' } //false
There isn't any way around it with Set. One thing I've done in a similar situation is loop through the array and create a dictionary (either with a JavaScript Object or Map), generating a unique key for each item, then iterating through that Object or Map to get the unique times.
For example, in your case, something like:
const availableTimesMap = availableTimes.reduce((acc, timeObject) => {
const key = `${timeObject.type}-${timeObject.time}`;
acc[key] = timeObject;
}, {});
const uniqueTimes = Object.values(availableTimesMap);
Hope this helps. Let me know if you have any questions.
I had a similar issue in my own project. To solve it I ended up having to use strings to be the keys of a Map object. You would need to figure out a standard way to ID a time so that two "identical" times are converted to identical strings. Simply using the time would probably work well enough.
const timesAvailable = new Map()
businessList.forEach(item =>
item.availableTimes.forEach(item =>
timesAvailable.add(item.time, item)
)
)
Alternatively, you could do away with objects and just use the string times.
[
{"availableTimes": ["06:30", "07:00"]},
{"availableTimes": ["08:30", "07:00"]}
]
I am not sure what the structure of the result you want to get. I assume that if you want to get a set of non-duplicate objects and each object looks like this: {"type": "time", "time": "06:30"}.
let businessList = [
{"availableTimes": [{"type": "time", "time": "06:30"}, {"type": "time", "time": "07:00"}]},
{"availableTimes": [{"type": "time", "time": "08:30"}, {"type": "time", "time": "07:00"}]}
]
const timesAvailable = new Set(); // a set of strings representing time, which is used for checking duplicates
const availableBusiness = new Set(); //the result we want
for(let business of businessList) {
for (let availableTime of business.availableTimes) {
if(availableTime.type === "time") {
if(!timesAvailable.has(availableTime.time)){
timesAvailable.add(availableTime.time);
availableBusiness.add(availableTime);
}
}
}
}
console.log(availableBusiness);
console.log(timesAvailable);
I'd like to know if one can use .map() to dynamically change the added value to JS objects.
For example, a static use of .map() allows to add a similar ID to all objects of the array.
friends = [
{
"age": 10,
"name": "Castillo"
},
{
"age": 11,
"name": "Daugherty"
},
{
"age": 12,
"name": "Travis"
}
]
// Static mapping --> adds 1 to all objects
friends_static=friends;
friends.map(elem => elem["id"] = 1);
console.log(friends_static)
This returns [{age=10, name="Castillo", id=1}, {age=11, name="Daugherty", id=1}, {age=12, name="Travis", id=1}]
Is it possible to add a unique ID which increments by 1 for each object in a similar way?
Cf. the illustrative JSfiddle and example code below. I know the 1++ is not legal, but just shows the idea I'm trying to realize.
//Dynamic mapping? --> should add 1,2,3...to objects incrementally
/*
friends_dynamic=friends;
friends.map(elem => elem["id"] = 1++);
console.log(friends_dynamic)
*/
This should return [{age=10, name="Castillo", id=1}, {age=11, name="Daugherty", id=2}, {age=12, name="Travis", id=3}]
You could just use the index provided to the Array#map callback:
friends.map((friend, index) => Object.assign({}, friend, { id: index + 1 }))
It's not a good idea to mutate objects in Array#map. The whole purpose of the method is to return new objects that are mapped from the original objects. Thus use Object.assign to avoid mutation.
Of course, if you wanted mutation, thus just use forEach without mapping to new values. It would be more "semantically correct" in that case.
Is this what you mean?
const friends = [
{
"age": 10,
"name": "Castillo"
},
{
"age": 11,
"name": "Daugherty"
},
{
"age": 12,
"name": "Travis"
}
]
friends.forEach((friend, index) => friend.id = index + 1);
console.log(friends)
if you only need an incremental value from 0 on, you can simply use a counter and increment it, like this:
let id = 1;
friends.map(elem => {elem.id = id++;});
Use a local variable and increment it. As per method definition
"The map() method calls the provided function once for each element in an array, in order". In Order would make sure that ids do not collide.
friends = [
{
"age": 10,
"name": "Castillo"
},
{
"age": 11,
"name": "Daugherty"
},
{
"age": 12,
"name": "Travis"
}
]
// Static mapping --> adds 1 to all objects
friends_static=friends;
var i = 1;
friends_static.map(elem => elem["id"] = i++);
console.log(friends_static)
//Dynamic mapping? --> should add 1,2,3...to objects incrementally
/*
friends_dynamic=friends;
friends_dynamic.map(elem => elem["id"] = 1++);
console.log(friends_dynamic)
*/
I'm trying to create a JSON object with a nested array of JSON objects. What is the correct format of this?
Here is an example what I am trying to create:
{
"reviewCount": 96,
"reviews": [
{"name": "Sean Steinman", "date": "reviewed 2 weeks ago", "reviewContent": "Fantastic Service"},
{"name": "Ryan Lundell", "date": "reviewed in the last week", "reviewContent":"Ask for Scott!"}
]
}
Here is what I have so far:
var reviewObj = {
reviewCount: reviews.length,
reviews: [{name: , date: , reviewContent:}]
}
After I initialize it, I will fill it with a for loop that runs through an existing array of strings.
CLARIFICATION:
The array that I'm using to populate the JSON object is:
[
"\nSean Steinman\nreviewed 2 weeks ago\n Fantastic Service\n",
"\nRyan Lundell\nreviewed in the last week\n Ask for Scott!\n• • •\n"
]
So I'm creating a new array in my for with tmpArr = reviews[i].split('/n');, and then where I'm getting stuck is how to stick that into the JSON object as an object.
First, you're not building a "JSON" object. You're just building an object. It's not JSON until you JSON-encode it. {"name": "bob"} is not JSON, it's an object literal. '{"name": "bob"}', the string, is JSON.
Second, you cannot loop inside an object literal, which is what your second code example seems to indicate you're trying to do. Instead, you need to initialize you reviews property to an empty array, and then loop and append items to the array.
var reviews = [
"\nSean Steinman\nreviewed 2 weeks ago\n Fantastic Service\n",
"\nRyan Lundell\nreviewed in the last week\n Ask for Scott!\n• • •\n"
];
var reviewObj = {
reviewCount: reviews.length,
reviews: []
}
reviews.forEach(function(line) {
var review = line.split("\n");
reviewObj.reviews.push({name: review[0], date: review[1], reviewContent: review[2]});
});
I am trying to parse the following JSON with jQuery and get each id value. Can anyone advise?
[
{
"id": "1",
"name": "Boat"
},
{
"id": "2",
"name": "Cable"
}
]
So far I have:
$.each(test, function(i,item){
alert(item);
});
But that simply lists every value. How can I
That'll list every object in your array, to get the id property of the one you're on, just add .id like this:
$.each(test, function(i,item){
alert(item.id);
});
If test is a string containing JSON, you can parse it with jQuery.parseJSON, which will return a JavaScript object.
If test is written like this:
var test = [
{
"id": "1",
"name": "Boat"
},
{
"id": "2",
"name": "Cable"
}
];
...it already is a JavaScript object; specifically an array. jQuery.each will loop through each array entry. If you want to loop through the properties of those entries as well, you can use a second loop:
$.each(test, function(outerKey, outerValue) {
// At this level, outerKey is the key (index, mostly) in the
// outer array, so 0 or 1 in your case. outerValue is the
// object assigned to that array entry.
$.each(outerValue, function(innerKey, innerValue) {
// At this level, innerKey is the property name in the object,
// and innerValue is the property's value
});
});
Live example