I have a array of objects for use in D3 e.g
var cities = [
{ city: "London", country: "United Kingdom", index: 280 },
{ city: "Geneva", country: "Switzerland", index: 259 },
{ city: "New York City", country: "United States", index: 237 },
{ city: "Singapore", country: "Singapore", index: 228 },
{ city: "Paris", country: "France", index: 219 },
{ city: "San Francisco", country: "United States", index: 218 },
{ city: "Copenhagen", country: "Denmark", index: 217 },
{ city: "Sydney", country: "Australia", index: 215 },
{ city: "Hong Kong", country: "Hong Kong", index: 214 },
{ city: "Brisbane", country: "Australia", index: 208 }
}
I would like to order the objects in ascending order based on their cities.index property. So that I can display them as such in D3.js. Im sure there is a way of doing this in D3 but I am yet to figure it out when dealing with an array of objects.
Any help?
You can pass an anonymous function to the Javascript Array.prototype.sort to sort by index. D3 has a function d3.ascending (v 3.x) that makes it easy to sort ascending:
cities.sort(function(x, y){
return d3.ascending(x.index, y.index);
})
And here's the output:
[
{"city":"Brisbane","country":"Australia","index":208},
{"city":"Hong Kong","country":"Hong Kong","index":214},
{"city":"Sydney","country":"Australia","index":215},
{"city":"Copenhagen","country":"Denmark","index":217},
{"city":"San Francisco","country":"United States","index":218},
{"city":"Paris","country":"France","index":219},
{"city":"Singapore","country":"Singapore","index":228},
{"city":"New York City","country":"United States","index":237},
{"city":"Geneva","country":"Switzerland","index":259},
{"city":"London","country":"United Kingdom","index":280}
]
Just sort the array before you use it in D3, as Travis J mentioned in a comment. There's no reason to use D3 to sort (d3.ascending is just a comparison wrapper anyway).
Also, note that you have a } where you want a ] at the end of your declaration.
You can access each object's properties as so:
cities.sort(function(a, b){
return a["index"]-b["index"];
});
As #Casey Falk said d3.sort is an elegant method in d3 library. I code the following to solve my problem:
const axisGrid = svg.append("g")
const photoGroup = axisGrid.append("g")
.selectAll("g")
.data(photo_data)
.enter()
.append("g")
const photos = photoGroup.append("image");
photos.on("mouseenter", function(curItem) {
// selection.sort(compare) https://github.com/d3/d3-selection/blob/v3.0.0/README.md#selection_sort
photoGroup.sort((a, b) => {
if (a.photo == curItem.photo) { // make the current image element on top
return 1
} else {
return -1
}
})
Related
I have a json file converted into a js object
var factory = {
city: "turin",
street: "corso unione sovietica",
nAddres: 74,
operative: true,
models: ["toyota", "chevrolet", "ford", "subaru", "honda"],
workspace: {
offices: 12,
minsOfPause: 15,
},
cars: {
toyota: {
id: 1,
numberPlate: "S4IIPLE",
broken: false,
insurance: null,
previousOwners: ["Mark", "Sebastian", "Carlos"],
infos: {
parketAt: "425 2nd Street",
city: "San Francisco",
state: "CA",
postalCode: 94107,
},
},
chevrolet: {
id: 2,
numberPlate: "S2IALR",
broken: true,
insurance: null,
previousOwners: ["Robert", "Mark"],
infos: {
parketAt: "711-2880 Nulla St",
city: "Mankato",
state: "MS",
postalCode: 96522,
},
},
},
};
var json = JSON.stringify(factory);
json = JSON.parse(json);
I have to display the data in a ul li list in an HTML file but when I try to iterate the objects with
for(var a in json){
console.log(a);
}
the console says that the object is not iterable
and with
for(var a of json){
console.log(a);
the console doesn't display the value
pls help
A for...of loop is used to loop through an array.
For an object, we should use for...in loop.
Here, it should be :
for (let a in json){
console.log(a);
}
I have an array of objects where I want to find out what consecutive days are the most common between all of them and then choose the first day of that consecutive day pair.
let data = [
{
name: "mike",
city: "Los Angeles",
days: ["2020-01-02", "2020-01-03","2020-01-18", "2020-01-19"]
},
{
name: "Kenny",
city: "Chicago",
days: ["2020-04-02", "2020-04-12","2020-04-19"]
},
{
name: "James",
city: "Los Angeles",
days: ["2020-05-02", "2020-05-12","2020-05-19"]
},
{
name: "Maggie",
city: "Los Angeles",
days: ["2020-11-12", "2020-11-13","2020-05-19"]
},
{
name: "Ricardo",
city: "Los Angeles",
days: ["2020-01-02", "2020-01-03","2020-05-19"]
},
{
name: "Reeny",
city: "Chicago",
days: ["2020-01-02", "2020-01-04","2020-05-09"]
},
];
so for example, for Los Angeles, I'd want to return:
{
city: "Los Angeles",
day: "2020-01-02",
people: ["mike", "ricardo"],
}
"Maggie" wouldn't be in since her available consecutive days appear less than Mike and James.
For Mike and James, "2020-01-02" and "2020-01-03" appears most for Los Angeles.
For Chicago, I'd want to return just an empty string since I don't have any consecutive days.
So far, I iterated through the data and pushed the city to an object. If the city is already in the object, I push each day to the existing array. If the city is not in the hash object, then I just set it and have it equal the days
let obj = {};
data.forEach(x => {
if (map[x.city]) {
x.days.forEach(y => {
map[x.city].push(y);
})
} else {
map[x.city] = x.days;
}
});
for (x in obj) {
let arr = [...new Set(obj[x])]
obj[x] = arr.sort();
}
my result is an object with the city as a key and the value is the days (with the duplicates removed via Set) :
obj = {
"Los Angeles": ["2020-01-02", "2020-01-03","2020-01-18", "2020-01-19", "2020-05-02", "2020-05-12","2020-05-19", "2020-11-12", "2020-11-13"],
"Chicago": ["2020-01-02", "2020-01-04","2020-04-02", "2020-04-12","2020-04-19", "2020-05-09"]
}
From this point, I'm not sure what to do. I imagine it's possible to accomplish this but I don't know the next step here.
You can use alasql
https://github.com/agershun/alasql/wiki/Examples
with alasql can you make: DISTINCT or GROUP etc.
example:
// Fill table with data
var person = [
{ name: 'bill' , sex:'M', income:50000 },
{ name: 'sara' , sex:'F', income:100000 },
{ name: 'larry' , sex:'M', income:90000 },
{ name: 'olga' , sex:'F', income:85000 },
];
// Do the query
var res = alasql("SELECT * FROM ? person WHERE sex='F' AND income > 60000", [person]);
document.getElementById("result").innerHTML = JSON.stringify(res);
thanks for taking a look at this. Sorry for length, trying to be clear!
WHAT I'M TRYING TO DO:
I have an array of users (each user an object) and am trying to filter the users on multiple criteria ("males from France" OR "females from Spain and United States with Engineering skills" etc) but it's proven beyond my skills so far.
The hard part has been that the users are objects within a User array, but within each user object, some values are additional objects or arrays. Here's what the user data array looks like (abbreviated):
let users = [
{
gender: 'male',
location: {street: 'Clement Street', country: 'United States'},
skills: ['engineering', 'underwater'],
}, ...
Notice gender is just a normal property/value but country is within a location object and skills are within an array.
I already have a search button interface that creates toggle buttons to search on each criteria available, and every time you click a button, I add or remove that criteria in a filter object. The filter object looks like this, and uses arrays inside it so that I can define multiple criteria at once, like multiple countries to search, multiple skills, etc.:
filter: {
gender: ['female'],
location: {
country: ['Spain'],},
skills: ['optics', ]
},
WHERE I REALLY GET STUCK
I've created a filterData method that can successfully filter based on Gender (male or female) but can't get it to ALSO filter on country (within the location object) or skills (within the skills array). My current filterData method only goes through one iteration per user, but I've tried For loops and forEach to try to go through each of the filter's criteria ('Spain', 'Optics'), but it just doesn't work. I only get gender.
I think I have two problems: 1) somehow conveying in the code that the item 'key' in some cases will not be a value, but an object or array that must also be searched within, and 2) creating some kind of looping behavior that will go through each of the filter criteria, instead of stopping after the first one (gender).
That's apparently over my head right now, so any guidance or suggestions would be appreciated, thanks very much! And here's all the code I've been working with, including my filterData method.
var filtering = {
filter: {
gender: ["female"],
location: {
country: ["Spain"],
},
skills: ["optics"],
},
users: [
{
gender: "male",
name: "John",
location: { street: "Clement Street", country: "United States" },
skills: ["engineering", "underwater"],
},
{
gender: "female",
name: "Mary",
location: { street: "5th Avenue", country: "Spain" },
skills: ["confidence", "optics"],
},
{
gender: "male",
name: "David",
location: { street: "Vermont Ave", country: "France" },
skills: ["cards", "metalurgy", "confidence"],
},
{
gender: "female",
name: "Rachel",
location: { street: "Vermont Ave", country: "France" },
skills: ["disguise", "electrical"],
},
{
gender: "female",
name: "Muriel",
location: { street: "Vermont Ave", country: "Germany" },
skills: ["flight", "surveillance"],
},
],
filterData: (filter) => {
const filteredData = filtering.users.filter((item) => {
for (let key in filter) {
if (!filter[key].includes(item[key])) {
return false;
}
return true;
}
});
console.log(filteredData);
},
};
filtering.filterData(filtering.filter);
There's a nifty trick called recursion, which is a function calling itself.
The updated code are: checkUserand
filterData
var filtering = {
filter: {
gender: ["female"],
location: {
country: ["Spain"],
},
skills: ["optics"],
},
users: [
{
gender: "male",
name: "John",
location: { street: "Clement Street", country: "United States" },
skills: ["engineering", "underwater"],
},
{
gender: "female",
name: "Mary",
location: { street: "5th Avenue", country: "Spain" },
skills: ["confidence", "optics"],
},
{
gender: "male",
name: "David",
location: { street: "Vermont Ave", country: "France" },
skills: ["cards", "metalurgy", "confidence"],
},
{
gender: "female",
name: "Rachel",
location: { street: "Vermont Ave", country: "France" },
skills: ["disguise", "electrical"],
},
{
gender: "female",
name: "Muriel",
location: { street: "Vermont Ave", country: "Germany" },
skills: ["flight", "surveillance"],
},
],
checkUser (filter, to_check) {
if (Array.isArray(filter))
{
return Array.isArray(to_check)
? filter.some(val => to_check.includes(val)) // if what we're checking is an array
: filter.includes(to_check); // otherwise it's a singular value
}
else
{
const all_checks = []; // this is to save every return value from the recursive function
for (let key in filter) // going through each key in the filter
{
const checked = this.checkUser(filter[key], to_check[key]) // passing two values, which will be compared with each other
all_checks.push(checked) // pushing the checked result
}
return all_checks.every(val => val) // checking that it passes the filter by ensuring every value is true
}
},
filterData () {
let filter = this.filter
return this.users.filter(user => this.checkUser(filter, user))
},
};
// filtering.filterData(filtering.filter);
// filtering.checkUser(filtering.filter, filtering.users[0])
const result = filtering.filterData()
console.log(result)
Bit complex data structure, you should clean. However, solved what expected.
const mergeFilter = (item, [key, value]) => {
let val = Array.isArray(item[key]) ? item[key] : [item[key]];
let m = value[0];
if (typeof value === "object" && !Array.isArray(value)) {
const k2 = Object.keys(value);
val = item[key][k2];
m = value[k2][0];
}
return val.includes(m);
};
const filterData = (users, filter) => {
const filters = Object.entries(filter);
const result = users.reduce((arr, item) => {
let found = filters.every(mergeFilter.bind(null, item));
if (found) arr.push(item);
return arr;
}, []);
return result;
};
var filtering = {"filter":{"gender":["female"],"location":{"country":["Spain"]},"skills":["optics"]},"users":[{"gender":"male","name":"John","location":{"street":"Clement Street","country":"United States"},"skills":["engineering","underwater"]},{"gender":"female","name":"Mary","location":{"street":"5th Avenue","country":"Spain"},"skills":["confidence","optics"]},{"gender":"male","name":"David","location":{"street":"Vermont Ave","country":"France"},"skills":["cards","metalurgy","confidence"]},{"gender":"female","name":"Rachel","location":{"street":"Vermont Ave","country":"France"},"skills":["disguise","electrical"]},{"gender":"female","name":"Muriel","location":{"street":"Vermont Ave","country":"Germany"},"skills":["flight","surveillance"]}]}
const result = filterData(filtering.users, filtering.filter);
console.log(result)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have feature in my application that should allow users to select items in drop down menu and move them up and down. Once they select and click on the button I have to loop over the array of objects and pull only records that were selected in drop down menu. Here is example of my code:
var selectedColumns = ['first','last','city'];
var data = [
{
first: "Mike",
last: "Ross",
dob: "05/26/1978",
city: "Washington DC",
state: "DC",
zip: 22904
},
{
first: "John",
last: "Henderson",
dob: "11/06/1988",
city: "Iowa City",
state: "IA",
zip: 52401
},
{
first: "Nina",
last: "Barkley",
dob: "01/16/1968",
city: "New York",
state: "NY",
zip: 11308
},
{
first: "Jessie",
last: "Kuch",
dob: "02/02/1956",
city: "Des Moines",
state: "IA",
zip: 55432
},
{
first: "Jenny",
last: "Terry",
dob: "012/28/1988",
city: "Miami",
state: "FL",
zip: 83943
}
]
In selected column we only have first, last and city. Then I have to loop over data and pull only selected columns. One way to do that is like this:
for(var key in data){
for(var i=0; i<selectedColumns.lenght; i++){
var columnID = String(columns[i]);
console.log($.trim(data[key][columnID]));
}
}
While this solution works just fine, I'm wondering if there is better way to avoid inner loop and improve efficiency? I use JQuery/JavaScript in my project. If anyone knows a better way to approach this problem please let me know. Thank you.
You can use Array.map, Array.reduce and Object.assign
var selectedColumns = ['first','last','city'];
var data = [{first: "Mike",last: "Ross",dob: "05/26/1978",city: "Washington DC",state: "DC",zip: 22904},{first: "John",last: "Henderson",dob: "11/06/1988",city: "Iowa City",state: "IA",zip: 52401},{first: "Nina",last: "Barkley",dob: "01/16/1968",city: "New York",state: "NY",zip: 11308},{first: "Jessie",last: "Kuch",dob: "02/02/1956",city: "Des Moines",state: "IA",zip: 55432},{first: "Jenny",last: "Terry",dob: "012/28/1988",city: "Miami",state: "FL",zip: 83943}];
let result = data.map(o => selectedColumns.reduce((a,c) => Object.assign(a,{[c]:o[c]}), {}));
console.log(result);
EDIT
var selectedColumns = ['dob','last','city'];
var data = [{first: "Mike",last: "Ross",dob: "01/01/1900",city: "Washington DC",state: "DC",zip: 22904},{first: "John",last: "Henderson",dob: "11/06/1988",city: "Iowa City",state: "IA",zip: 52401},{first: "Nina",last: "Barkley",dob: "01/16/1968",city: "New York",state: "NY",zip: 11308},{first: "Jessie",last: "Kuch",dob: "02/02/1956",city: "Des Moines",state: "IA",zip: 55432},{first: "Jenny",last: "Terry",dob: "012/28/1988",city: "Miami",state: "FL",zip: 83943}];
let result = data.map(o => selectedColumns.reduce((a,c) => {
if(c === 'dob' && o[c] === '01/01/1900') a[c] = 'N/A';
else a[c] = o[c];
return a;
}, {}));
console.log(result);
Another important thing to mention is that it's generally a bad idea to use for ... in construct to iterate over array items in JavaScript (see Why is using "for...in" with array iteration a bad idea? for some explanations).
Just a single line of code by mapping the wanted properties.
Array#map for getting a new array of data and for mapping the wanted keys as new objects witk
computed property names and the value, assigned to a single object with
Object.assign and
spread syntax ... for taking an array as arguments.
var selectedColumns = ['first','last','city'],
data = [{ first: "Mike", last: "Ross", dob: "05/26/1978", city: "Washington DC", state: "DC", zip: 22904 }, { first: "John", last: "Henderson", dob: "11/06/1988", city: "Iowa City", state: "IA", zip: 52401 }, { first: "Nina", last: "Barkley", dob: "01/16/1968", city: "New York", state: "NY", zip: 11308 }, { first: "Jessie", last: "Kuch", dob: "02/02/1956", city: "Des Moines", state: "IA", zip: 55432 }, { first: "Jenny", last: "Terry", dob: "012/28/1988", city: "Miami", state: "FL", zip: 83943 }],
result = data.map(o => Object.assign(...selectedColumns.map(k => ({ [k]: o[k] }))));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You will find Array.filter suits this use-case
var words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => {
return word.length > 6;
});
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
You could look into using filters where you build the filtering method based on the search criteria and return the filtered array.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
const newArr = oldArr.filter(record => record.first === 'Nina')
//newArr would only have Nina's record
alternatively if you are trying to go by having a particular field you can still use filter as well
var newArr2 = data.filter(record => record.hasOwnProperty('first'))
// newArr2 would have all records with the property name
I am meeting now the difficult problem for me that hurt my heart,
I want to convert [01] JSON to [02].
[01] JSON :
{locations: [
{
country: "Australia",
area: "NSW",
city: "Gordon"
},
{
country: "Australia",
area: "NSW",
city: "Chatswood"
}
]};
[02] JSON :
{countries: [
{
name: "Australia",
areas: [
{
name: "NSW",
cities: [
{
name: "Gordon"
},
{
name: "Chatswood"
}
]
}
]
}
]}
Since you're going to be doing a bunch of lookups I suggest using a collection of objects rather than your final structure with arrays. You can then either convert it to the final structure or modify code to use it the way it is.
var countries = {};
for (var i=0, loc; loc = locations[i]; i++) {
if (!countries[loc.country]) countries[loc.country] = {};
if (!countries[loc.country][loc.area]) countries[loc.country][loc.area] = [];
countries[loc.country][loc.area].push(loc.city);
}
alert(JSON.stringify(countries));