Hi Everyone,
I have this object:
{"2017-07-09 00:00:00":4,"2017-07-09 09:00:00":1,"2017-07-09 10:00:00":4,"2017-07-09 11:00:00":3,"2017-07-09 12:00:00":16,"2017-07-09 13:00:00":4,"2017-07-09 14:00:00":6,"2017-07-09 15:00:00":5,"2017-07-09 16:00:00":7,"2017-07-09 17:00:00":21,"2017-07-09 18:00:00":25,"2017-07-09 19:00:00":1,"2017-07-10 09:00:00":11,"2017-07-10 10:00:00":4,"2017-07-10 11:00:00":21,"2017-07-10 12:00:00":22,"2017-07-10 13:00:00":23,"2017-07-10 14:00:00":42,"2017-07-10 15:00:00":14,"2017-07-10 16:00:00":36,"2017-07-10 17:00:00":21,"2017-07-10 18:00:00":5,"2017-07-11 09:00:00":16,"2017-07-11 10:00:00":7,"2017-07-11 11:00:00":26,"2017-07-11 12:00:00":34,"2017-07-11 13:00:00":39,"2017-07-11 14:00:00":39,"2017-07-11 15:00:00":30,"2017-07-11 16:00:00":33,"2017-07-11 17:00:00":22,"2017-07-11 18:00:00":1}
I'm trying to divide it per day and get something like this:
First create an array for the day which is 24 hours:
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]
And than calculate how many day is in the object above and get a value for each hours and return something like below. In the object I have 3 days, so I need to return 3 arrays for each days:
[4,0,0,0,0,0,0,0,0,1,10,3,16,...],
[0,0,0,0,0,0,0,0,0,11,4,21,22,23,42,...]
[0,0,0,0,0,0,0,0,0,16,7,26,34,39,39,30,..]
For each hours which is not in the object data return 0 and for each hours that exist return the specified value on the object.
for example on the object the time starts from "2017-07-09 00:00:00":4 and it has the value of 4 and for each hours between that and "2017-07-09 09:00:00":1
return 0.
Any help appreciated. Thanks a lot for your time
You have first to loop into each keys of your object.
After that many solutions, one is to convert your keys into Date object and compare the hour of your object in a for loop.
And retrieve the right data by reconverting your Date obj into your obj property.
Edit
Access your property value without function by using Object.keys and findIndex
I've maybe misunderstand your requirement, but you've a good example
of how to do ;-)
Example of solution
var data ={"2017-07-09 00:00:00":4,"2017-07-09 09:00:00":1,"2017-07-09 10:00:00":4,"2017-07-09 11:00:00":3,"2017-07-09 12:00:00":16,"2017-07-09 13:00:00":4,"2017-07-09 14:00:00":6,"2017-07-09 15:00:00":5,"2017-07-09 16:00:00":7,"2017-07-09 17:00:00":21,"2017-07-09 18:00:00":25,"2017-07-09 19:00:00":1,"2017-07-10 09:00:00":11,"2017-07-10 10:00:00":4,"2017-07-10 11:00:00":21,"2017-07-10 12:00:00":22,"2017-07-10 13:00:00":23,"2017-07-10 14:00:00":42,"2017-07-10 15:00:00":14,"2017-07-10 16:00:00":36,"2017-07-10 17:00:00":21,"2017-07-10 18:00:00":5,"2017-07-11 09:00:00":16,"2017-07-11 10:00:00":7,"2017-07-11 11:00:00":26,"2017-07-11 12:00:00":34,"2017-07-11 13:00:00":39,"2017-07-11 14:00:00":39,"2017-07-11 15:00:00":30,"2017-07-11 16:00:00":33,"2017-07-11 17:00:00":22,"2017-07-11 18:00:00":1}
var dataKeys = Object.keys(data);
var dataKeysParsed = dataKeys.map(function(d){
return new Date(d);
});
var res =[];
for (var i=0;i<=23;i++){
var id = dataKeysParsed.findIndex(function(k){
return k.getHours() == i
});
res.push(id > -1 ? data[dataKeys[id]] : 0);
}
console.log(res);
im currently starting with couchDB and have a problem building a reduce function on dates.
The database consists of timeline data for different locations. Every entry has a 'locationId' (String), a 'datetime' ( Array saved in lexicographic form like [year,month,day,hour,minute,sec]), a value (double)
i want to find out, which is the lowest and highest datetime for every location where a value exist. The timeline values have different start- and enddates.
In a first attempt i used _stats on milliseconds:
map:
function(doc) {
emit(doc.locationId, new Date(doc.datetime[0],doc.datetime[1],doc.datetime[2], doc.datetime[3], doc.datetime[4], doc.datetime[5]).getTime() ) }
reduce: _stats
this delivers the correct min and max milliseconds per locationId.
Now i want to have the output in a more readable form (formatted date string)
I tried different ways, here is the last one:
- map delivers locationId as key and a Date as value
- reduce converts every Date to milliseconds,
find the earlist date using Math.min,
re-converting milliseconds into Date and return
map:
function(doc) {
emit(doc.locationId, new Date(doc.datetime[0], doc.datetime[1],doc.datetime[2], doc.datetime[3], doc.datetime[4], doc.datetime[5]) ) }
reduce:
function(keys, values) {
var timestamps = new Array(values.length);
var i = 0;
var date;
for( date in values ) { timestamps[i] = date.getTime(); i++; }
var min = Math.min.apply(null, timestamps);
return new Date(min);
}
This results in 'null' for value.
is it possible to have a formatted date output for this case?
I've found the solution:
map:
function(doc) {
if (doc.datetime && doc.plantId)
emit(doc.plantId, [new Date(doc.datetime[0],doc.datetime[1]-1,doc.datetime[2],doc.datetime[3],doc.datetime[4],doc.datetime[5],0), new Date()] )
}
reduce:
function(keys, values) {
values.sort();
var date = [values[0][0], values[values.length-1][0]];
return date;
}
result: (key=locationID, value=[earliestDate, latestDate])
When i have the following global variable on my application start :
events = [];
Then if i go fetch something with ajax with the following simplified code snippet :
events[0] = [];
setTimeout(function fetchEventsThisWeek(){
$.ajax({
url: '/event/getEventsBetweenDates',
type: 'POST',
data : { from_date : currentweek.from_date.toString("yyyy-MM-d") , to_date : currentweek.to_date.toString("yyyy-MM-d"), limit : limit, offset : offset },
success: function(data) {
jQuery.each(data, function(index){
events[0].push(data[index]['attributes']);
});
offset = offset + limit;
entry_count = entry_count + data.length;
if(data.length < limit) { // We reached the end of the table so we don't need to call the function again
renderEvents(current, offset - limit, entry_count);
//Make sure the current next week button gets enabled because we are done with the results
} else {
renderEvents(current, offset - limit, offset);
setTimeout(fetchEventsThisWeek, 150); // There are more results, continue
}
}
})
}, 150);
This recursive function just fetches all events between two dates and keeps calling itself until there is no record in the db left.
My problem is:
With the variable:
events[0] = [];
I want to specify the index of the array as my week entry. So if i look for a specific week, i can get all the entries that already have been fetched from my array by the array index.
My problem is, when i want to fetch more weeks, so for example:
events[1] = [];// Index 1 would represent the next week
The array just expands in size and all gets appended to the end, so i have one big array and not a multidimensional one. Why is this? And how can i achieve this behaviour?
Edit:
Let me expand on my question.
I need several arrays of json objects in the events variable.
So..
events[0] = [ /*contains array of json objects */];
events[1] = [ /*contains array of json objects */];
events[2] = [ /*contains array of json objects */];
Each array index represent 1 week. So index 0 is the current week, index 1 is week 1, index 2 is week 2 and so forth. I even want to do the following but i don't know if this is even possible:
events[-1] = [ /*contains array of json objects */];
Where the index -1 would be 1 week in the past. Could anybody let me know if this is possible?
You're looking for Array.unshift:
events.unshift([]);
Documentation
I'm attempting to use the crossfilter javascript library (in conjunction with D3.js) to group and filter json data.
My json data has the following fields: week_date, category, team_name, title, subtitle
I've been able to successfully group on all records to produce YTD totals, using something like this:
var dimension = data.dimension(function(d) { return d[target]; });
var dimensionGrouped = dimension.group().all();
Where target is either category or team_name.
In addition to keeping the YTD totals, I also want to display totals for a given range. For example, a user-selected week (i.e. Oct 1st - 5th).
How do I create a filtered group which returns the totals for a given date range? Using my week_date field.
Well, after some superficial research, including skimming over crossfilter's issues list, I've concluded that crossfilter does not currently support grouping on multiple fields.
I was able to work around this by using a filtered copy of the data instead, as such:
// YTD rows
var crossfilterData = crossfilter(data);
var ytdDimension = crossfilterData.dimension(function(d) { return d[target]; });
var ytdDimensionGrouped = ytdDimension.group().all();
ytdDimensionGrouped.forEach(function (item) {
// ...
});
// Ranged rows
var filteredData = data.filter(function (d) {
return d.week_date >= filter[0] && d.week_date <= filter[1];
});
crossfilterData = crossfilter(filteredData);
var rangeDimension = crossfilterData.dimension(function(d) { return d[target]; });
var rangeDimensionGrouped = rangeDimension.group().all();
rangeDimensionGrouped.forEach(function (item) {
// ...
});
I have an array of data get from the server(ordered by date):
[ {date:"2012-8", name:"Tokyo"}, {date:"2012-3", name:"Beijing"}, {date:"2011-10", name:"New York"} ]
I'd like to :
get the name of the first element whose date is in a given year, for example, given 2012, I need Tokyo
get the year of a given name
change the date of a name
which data structure should I use to make this effective ?
because the array could be large, I prefer not to loop the array to find something
Since it appears that the data is probably already sorted by descending date you could use a binary search on that data to avoid performing a full linear scan.
To handle the unstated requirement that changing the date will then change the ordering, you would need to perform two searches, which as above could be binary searches. Having found the current index, and the index where it's supposed to be, you can use two calls to Array.splice() to move the element from one place in the array to another.
To handle searches by name, and assuming that each name is unique, you should create a secondary structure that maps from names to elements:
var map = {};
for (var i = 0, n = array.length; i < n; ++i) {
var name = array[i].name;
map[name] = array[i];
}
You can then use the map array to directly address requirements 2 and 3.
Because the map elements are actually just references to the array elements, changes to those elements will happen in both.
Assuming you are using unique cities, I would use the city names as a map key:
cities = {
Tokyo: {
date: "2012-8"
},
New York: {
date: "2011-10"
}
}
To search by date:
function byDate(date) {
for(el in cities) {
if(cities.hasOwnProperty(el) && cities[el].date === date)
return el;
}
}
Just for the record: without redesigning your date structure you could use sorting combined with the Array filter or map method:
function sortByDate(a,b){
return Number(a.date.replace(/[^\d]+/g,'')) >
Number(b.date.replace(/[^\d]+/g,''));
}
var example = [ {date:"2012-8", name:"Tokyo"},
{date:"2012-3", name:"Beijing"},
{date:"2011-10", name:"New York"} ]
.sort(sortByDate);
//first city with year 2012 (and the lowest month of that year)
var b = example.filter(function(a){return +(a.date.substr(0,4)) === 2012})[0];
b.name; //=> Beijing
//year of a given city
var city = 'Tokyo';
var c = example.filter(function(a){return a.city === city;})[0];
c.year; //=> 2012
//change year of 'New York', and resort data
var city = 'New York', date = '2010-10';
example = example.map(
function(a){if (a.name === city) {a.date = date;} return a;}
).sort(sortByDate);