Javascript collection find values with Lodash - javascript

I have an array shown as below. I want to know which values inside departure and arrival fields.
Array :
var data = {
"origin": "Antalya",
"destination": "IST",
"flights": [{
"provider": "thy",
"time": "2017-07-07 10:30",
"legs": [{
"departure": "AYT",
"arrival": "IST"
}]
},{
"provider": "thy",
"time": "2017-07-07 14:30",
"legs": [{
"departure": "AYT",
"arrival": "ESB"
},{
"departure": "ESB",
"arrival": "IST"
}]
},{
"provider": "pegasus",
"time": "2017-07-07 06:30",
"legs": [{
"departure": "AYT",
"arrival": "ADB"
},{
"departure": "ADB",
"arrival": "IST"
}]
}]
};
I want to new array like this :
["AYT","IST","ESB","ADB"]
How can i handle it using lodash?

Here's a solution using lodash:
let result = _(data.flights)
.flatMap('legs')
.flatMap(_.values)
.uniq()
.value();
First we get a flattened array of legs, transform that into a flattened array of the values of the properties of each leg, before finally getting the unique values.

Well loop through your data and create a string array, and then use the uniq function, like:
var data = {"origin":"Antalya","destination":"IST","flights":[{"provider":"thy","time":"2017-07-07 10:30","legs":[{"departure":"AYT","arrival":"IST"}]},{"provider":"thy","time":"2017-07-07 14:30","legs":[{"departure":"AYT","arrival":"ESB"},{"departure":"ESB","arrival":"IST"}]},{"provider":"pegasus","time":"2017-07-07 06:30","legs":[{"departure":"AYT","arrival":"ADB"},{"departure":"ADB","arrival":"IST"}]}]};
var legs = [];
_.each(data.flights, flight => {
_.each(flight.legs, leg => {
legs.push(leg.departure);
legs.push(leg.arrival);
});
});
console.log(_.uniq(legs));
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>

Related

Destructuring a json object in Javascript

How would access the _id and state values?
Here's the data
{
"data": {
"totalSamplesTested": "578841",
"totalConfirmedCases": 61307,
"totalActiveCases": 3627,
"discharged": 56557,
"death": 1123,
"states": [
{
"state": "Lagos",
"_id": "O3F8Nr2qg",
"confirmedCases": 20555,
"casesOnAdmission": 934,
"discharged": 19414,
"death": 207
},
{
"state": "FCT",
"_id": "QFlGp4md3y",
"confirmedCases": 5910,
"casesOnAdmission": 542,
"discharged": 5289,
"death": 79
}
]
}
}
What you have shown is a string in JSON format. You can convert that to a JavaScript object and then start to get the values you need from it.
let str = ‘{
"data": {
"totalSamplesTested": "578841",
"totalConfirmedCases": 61307,
"totalActiveCases": 3627,
"discharged": 56557,
"death": 1123,
"states": [
{
"state": "Lagos",
"_id": "O3F8Nr2qg",
"confirmedCases": 20555,
"casesOnAdmission": 934,
"discharged": 19414,
"death": 207
},
{
"state": "FCT",
"_id": "QFlGp4md3y",
"confirmedCases": 5910,
"casesOnAdmission": 542,
"discharged": 5289,
"death": 79
}
]
}
} ‘;
(Note, I have put the string in single quotes so it can be shown properly here but in your code you need to put it in back ticks so it can span many lines)
Now convert it to a JavaScript object.
let obj = JSON.parse(str);
Now look closely at the string to see how the object is structured. It actually has just one item in it, data. And that is itself an object with several items, one of which is states which is an array.
So, obj.data.states[0] is the array’s first entry. That is an object and has _id and state items.
You can step through the array extracting the ._id and .state entries.

How to get specific data from object array?

I'm a beginner and would like to know how I can get a specific object from an array
I have an Array that looks like this:
data {
"orderid": 5,
"orderdate": "testurl.com",
"username": "chris",
"email": "",
"userinfo": [
{
"status": "processing",
"duedate": "" ,
}
]
},
To get the data from above I would do something like this:
return this.data.orderid
But how can I go deeper and get the status in userinfo?
return this.data.orderid.userinfo.status
doesn't work... anyone have any ideas?
A few points:
data is not an array, is an Object (see the curly braces, arrays have squared brackets). To be really precise, your syntax is invalid, but I assume you wanted to type data = { ... }, as opposed to data { ... }
Your syntax is almost correct, the only mistake you are making is that userinfo is an array, and arrays have numeric indexes (I.e. array[0], array[1]). What you are looking for is this.data.orderid.userinfo[0].status
Use data.userinfo[0].status to get the value (in your case this.data.userinfo[0].status)
var data = {
"orderid": 5,
"orderdate": "testurl.com",
"username": "chris",
"email": "",
"userinfo": [
{
"status": "processing",
"duedate": "" ,
}
]
};
console.log(data.userinfo[0].status);
User Info is an array, so you would need to access it using indexer like so:
return this.data.userinfo[0].status
MDN on arrays: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
You need to iterate over data.userinfo (it's an array)
var data = {
"orderid": 5,
"orderdate": "testurl.com",
"username": "chris",
"email": "",
"userinfo": [
{
"status": "processing",
"duedate": "" ,
}
]
};
data.userinfo.forEach(function(element) {
console.log(element.status);
});

Lodash: filter a nested object by multiple properties

Consider the following example:
var products = {
"Products": [{
"Title": "A",
"Categories": [{
"Name": "Type",
"Properties": ["Type 1", "Type 2", "Type 3"]
}, {
"Name": "Market",
"Properties": ["Market 1", "Market 2", "Market 3", "Market 4"]
}, {
"Name": "Technology",
"Properties": ["Tech 1", "Tech 2"]
}]
}, {
"Title": "B",
"Categories": [{
"Name": "Type",
"Properties": ["Type 1", "Type 3"]
}, {
"Name": "Market",
"Properties": "Market 1"
}, {
"Name": "Technology",
"Properties": ["Tech 1", "Tech 3"]
}]
}, {
"Title": "C",
"Categories": [{
"Name": "Type",
"Properties": ["Type 1", "Type 2", "Type 3"]
}, {
"Name": "Market",
"Properties": ["Market 2", "Market 3"]
}, {
"Name": "Technology",
"Properties": ["Tech 2", "Tech 3"]
}]
}]
}
I'm trying to filter products by their properties so consider I'm using an array to keep track of my selected filters:
var filters = ['Type 3', 'Tech 1'];
With these filters I would like to return product A and product B.
I currently have this:
var flattenedArray = _.chain(products).map('Categories').flatten().value();
var result= _.some(flattenedArray , ['Properties', 'Tech 1']);
But I'm stuck on how to combine the properties for a combined search.
Use _.filter() to iterate the products. For each product combine the list of properties using _.flatMap(), and use _.intersection() and _.size() to find the amount of filters that exist in the categories. Compare that to the original number of filters, and return comparison's response.
var products = {"Products":[{"Title":"A","Categories":[{"Name":"Type","Properties":["Type 1","Type 2","Type 3"]},{"Name":"Market","Properties":["Market 1","Market 2","Market 3","Market 4"]},{"Name":"Technology","Properties":["Tech 1","Tech 2"]}]},{"Title":"B","Categories":[{"Name":"Type","Properties":["Type 1","Type 3"]},{"Name":"Market","Properties":"Market 1"},{"Name":"Technology","Properties":["Tech 1","Tech 3"]}]},{"Title":"C","Categories":[{"Name":"Type","Properties":["Type 1","Type 2","Type 3"]},{"Name":"Market","Properties":["Market 2","Market 3"]},{"Name":"Technology","Properties":["Tech 2","Tech 3"]}]}]};
var filters = ['Type 3', 'Tech 1'];
var result = _.filter(products.Products, function(product) {
return filters.length === _(product.Categories)
.flatMap('Properties')
.intersection(filters)
.size();
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
If I understand you question correctly, this code may help:
_.filter(
products.Products,
product => _.difference(
filters,
_.chain(product.Categories).map(category => category.Properties).flatten().value()
).length === 0
);
It calculates a union of all properties for each product:
_.chain(product.Categories).map(category => category.Properties).flatten().value()
And then checks that it contains all filters array elements, using _.difference method.
Hope it helps.
another fancy way through _.conforms
var res = _.filter(
products.Products,
_.conforms({'Categories': function(categories) {
return _.chain(categories)
.flatMap('Properties') // flat arrays
.uniq() // remove dublicates
.keyBy() // transform to objects with Properties keys
.at(filters) // get objects values by filters
.compact() // remove undefineds
.size() // get size
.eq(filters.length) // compare to filters size
.value();
}
}))
This will work for a list of items where the givenProperty you want to filter on is either a string like 'doorColour' or an array of strings representing the path to the givenProperty like ['town', 'street', 'doorColour'] for a value nested on an item as town.street.doorColour.
It also can filter on more than one value so you could you just need pass in an array of substrings representing the string values you want to keep and it will retain items that have a string value which contains any substring in the substrings array.
The final parameter 'includes' ensures you retain these values if you set it to false it will exclude these values and retain the ones that do not have any of the values you specified in the substrings array
import { flatMap, path } from 'lodash/fp';
const filteredListForItemsIncludingSubstringsOnAGivenProperty = (items, givenProperty, substrings, including=true) => flatMap((item) =>
substrings.find((substring) => path(givenProperty)(item) && path(givenProperty)(item).includes(substring))
? including
? [item]
: []
: including
? []
: [item])(items);
E.g. fLFIISOAGP(contacts, ['person','name'], ['Joh','Pau',Pet']);
with items of structure {contact, business:null, personal:{name:'John'}}.
For the original question - this will also work - I would use this repeatedly on a list of items to filter with different keys to filter on more than one property.
const firstFilteredResult = filteredListForItemsIncludingSubstringsOnAGivenProperty(
products.Products,
["Categories", "0", "Properties"],
["Type 3"]);
const secondFilteredResult = filteredListForItemsIncludingSubstringsOnAGivenProperty(
firstFilteredResult,
["Categories", "2", "Properties"],
["Tech 1"]);
expect(secondFilteredResult[0]['Title']).to.equal( "A");
expect(secondFilteredResult[1]['Title']).to.equal( "B");
expect(secondFilteredResult.length).to.equal(2);

Extract from nested attribute

I have the following model attributes:
[{
"id": 1,
"details": {
"name": "Sun Tzu",
"height": "180",
},
"lists": [
[{
"coworkers": "company cool",
"friends": "School",
}],
[{
"coworkers": "company nice",
"friends": "Childhood",
}]
]
}]
Yes, I know it is confusing but I am trying to understand nested models.
I want to display in a view (a table row), all the friends of id:1 model.
For example: School, Childhood.
How do I do that?
Thanks in advance!
var friends = _.chain(data)
.findWhere({ id: 1 })
.result('lists')
.flatten(false)
.pluck('friends')
.value();
You can chain functions to get the output you are looking for
console.log(_.chain(data)
.find(function(currentObject) {
return currentObject.id === 1;
})
.pick("lists")
.flatten(false)
.pluck("friends")
.value());
Output
[ 'School', 'Childhood' ]

How to get values by making a comparison in this JSON result

I have this JSON. I need to first compare values in teams with values in html_content.position[i] where i should be a loop var, and then if comparison returns true then get the value. See this example:
html_content.position[0][0].toLowerCase() = "navegantes";
Then I should compare with each value in teams and if there is any key that es equal then I should get the value, taking the example, I should get this value:
"img\/magallanes.jpg"
Can any give me some help here?
The problem is with this code you are using:
html_content.position[0][0].toLowerCase() = "navegantes";
html_content.position actually is an array of arrays of arrays (though in your example data each inner array is only of length 1... is that always true?), so you need one more bracket operator on there to test the value of html_content.position[i][0][0]
Here is an example that incorporates your JSON data, looks through each team, and finds the corresponding position: (see below for working JSfiddle demo)
The solution code:
var matches = [];
for(var teamName in json.teams)
{
for(var i = 0, len = json.html_content.position.length; i < len; i++)
{
if(json.html_content.position[i][0][0].toLowerCase() === teamName.toLowerCase())
{
// found a match. do something with it..
matches[matches.length] = {Name: teamName, Value: json.teams[teamName]};
break;
}
}
}
The JSON: (for reference since previously was only published on 3rd party site)
var json = {
"response":true,
"teams":{
"navegantes":"img\/magallanes.jpg",
"tigres":"img\/tigres.jpg",
"caribes":"img\/caribes.jpg",
"leones":"img\/leones.jpg",
"aguilas":"img\/aguilas.jpg",
"tiburones":"img\/tiburones.jpg",
"bravos":"img\/bravos.jpg",
"cardenales":"img\/cardenales.jpg",
"maga":"img\/magallanes.jpg",
"tigr":"img\/tigres.jpg",
"cari":"img\/caribes.jpg",
"leon":"img\/leones.jpg",
"agui":"img\/aguilas.jpg",
"tibu":"img\/tiburones.jpg",
"brav":"img\/bravos.jpg",
"card":"img\/cardenales.jpg"
},
"html_content":{
"position":[
[
[
"Navegantes",
"14",
"10",
"4",
"0"
]
],
[
[
"Tigres",
"14",
"10",
"4",
"0"
]
],
[
[
"Caribes",
"14",
"9",
"5",
"1"
]
],
[
[
"Leones",
"14",
"9",
"5",
"1"
]
],
[
[
"Tiburones",
"13",
"5",
"8",
"4.5"
]
],
[
[
"Aguilas",
"14",
"5",
"9",
"5"
]
],
[
[
"Bravos",
"14",
"4",
"10",
"6"
]
],
[
[
"Cardenales",
"13",
"3",
"10",
"6.5"
]
]
],
"current":[
[
"MAGA",
"CARI",
"7:00 pm",
"PUERTO LA CRUZ"
],
[
"AGUI",
"LEON",
"4:00 pm",
"CARACAS"
],
[
"BRAV",
"TIGR",
"5:30 pm",
"MARACAY"
],
[
"TIBU",
"CARD",
"5:30 pm",
"BARQUISIMETO"
]
],
"next":[
[
"MAGA",
"CARI",
"6:00 pm",
"PUERTO LA CRUZ"
],
[
"AGUI",
"LEON",
"1:00 pm",
"CARACAS"
],
[
"TIBU",
"TIGR",
"5:30 pm",
"MARACAY"
],
[
"BRAV",
"CARD",
"2:00 pm",
"BARQUISIMETO"
]
],
"previous":[
]
}
};
See an example fiddle here: http://jsfiddle.net/VqHpJ/
The example fiddle creates an array of matches which is a collection of objects representing the team Name and the Value for the associated image, and spits them out in a list. (Of course, you didn't say what you want to do once you found a match, so you can adapt this as needed).
This is a fairly typical pattern for matching elements in two arrays (one nested loop), and in my example it assumes that only one match should be found, in which case it will break out of the nested loop and start looking for the next team. Therefore the performance is O(n^2) in the worst case.
This is a little tricky (but not difficult) because the teams object does not really have an array of teams, it has specific properties for each team name. Therefore the solution was to iterate over the properties of the teams object using for(var teamName in json.teams). If you are the author of the function that generates the JSON, you may want to consider revising it to instead generate an array of teams, for example:
var json = {
"response":true,
"teams":
[
{ "Name": "navegantes", "ImageUrl": "img\/magallanes.jpg" },
{ "Name": "tigres", "ImageUrl": "img\/tigres.jpg"},
{ "Name": "caribes", "ImageUrl": "img\/caribes.jpg"},
...
]
...
}
Assuming you have a JSON string that you parsed into an object that looks like the following
var json = {"teams":{
"navegantes":"img\/magallanes.jpg",
"tigres":"img\/tigres.jpg",
"caribes":"img\/caribes.jpg",
"leones":"img\/leones.jpg",
"aguilas":"img\/aguilas.jpg",
...
}};
You can iterate using each()
$.each(json.teams, function(i, v){
console.log(i);
console.log(v);
});

Categories

Resources