Gridster serialize data to 1-5 order (recursive loop)? - javascript

I'm using the Gridster plugin, and I need to capture the newly dragged order in an 1-5 manner. I know that we choose row first, then order (column). So, row:1, order:1 would be id: grid_74. The next closest order number greater than 1 in row 1 is 5, so id: grid_78. How can I accomplish this?
1 - grid_74
2 - grid_78
(etc...)
var gridinfo = gridster.serialize()

I think you might just need a sort.
// Just setting up object array to match example:
var gridinfo = [
{ id: "grid_75", order: 5, row: 4 },
{ id: "grid_74", order: 1, row: 1 },
{ id: "grid_91", order: 9, row: 1 },
{ id: "grid_85", order: 5, row: 7 },
{ id: "grid_78", order: 5, row: 1 }
]
// This sort is what does all the magic.. it first sorts by row, then order.
// I lifted this bit of javascript ninjutsu from:
// http://www.sitepoint.com/sophisticated-sorting-in-javascript/
gridinfo.sort(function(a, b)
{
if(a.row === b.row)
{
return a.order < b.order ? -1 : a.order > b.order ? 1 : 0;
}
return a.row - b.row;
});
// Display sorted array:
for(var k=0; k<gridinfo.length; k++)
{
document.write('id: '+gridinfo[k].id+'<br>');
document.write('row: '+gridinfo[k].row+'<br>');
document.write('order: '+gridinfo[k].order+'<br>');
document.write('-------<br>');
}

Related

Re-Map an array of Object based on sort order of a property

Let's see I have a data in following structure
[
{
"Id": "xyz7",
"CurrentRow": 0,
"ReportTime": "2022-07-18T09:00:00+00:00",
"ExitTime": null,
"DateField": "2022-07-18"
},
{
"Id": "xyz8",
"CurrentRow": 1,
"ReportTime": "2022-07-18T08:00:00+00:00",
"ExitTime": null,
"DateField": "2022-07-18"
},
{
"Id": "wxyz0",
"CurrentRow": 0,
"ReportTime": "2022-07-19T00:00:00+00:00",
"ExitTime": null,
"DateField": "2022-07-19"
},
{
"Id": "wxyz1",
"CurrentRow": 1,
"ReportTime": "2022-07-19T00:00:00+00:00",
"ExitTime": null
"DateField": "2022-07-19"
}
]
If I have to say sort the structure based on ReportTime of Date : 2022-07-18, that will change the CurrentRow of entries for DateField 2022-07-18 as
0 to 1 (as it will now belong to 1st Index) and for 2nd entry 1 - 0.
In addition, the CurrentRow of other entries (for other date shall also be adapted if they were same as that of day being sorted.)
In order to achieve this my implementation goes like,
I convert the structure to a two dimensional array based on CurrentRow.
Index in dimension 1, represents the CurrentRow.
The element of array will be an array of specific data entry like [entry_for_date_18,entry_for_date_19] (Kind of spread sheet with date as columns and CurrentRow as rows.
And then in order to sort, I pick all the entries for a particular date, sort it, and collect it with the original CurrentRow. (Pass 1).
Then I go and update the CurrentRow of original array, using the index (pass 2).
e.g pseudo code:
for(let i=0;i<sortedDayArray.length;i++){
findByInOriginalArray(sortedDayArray[i].CurrentRow).updateCurrentRowTo(i)
}
Was wondering if there is a better or more efficient way to do that, using map ?
This is how I got your question: you want to sort your array based on ReportTime, then re-arrange CurrentRow based on its position in DateField and this is the data you are expecting:
[
{
Id: 'xyz8',
CurrentRow: 0,
ReportTime: '2022-07-18T08:00:00+00:00',
ExitTime: null,
DateField: '2022-07-18'
},
{
Id: 'xyz7',
CurrentRow: 1,
ReportTime: '2022-07-18T09:00:00+00:00',
ExitTime: null,
DateField: '2022-07-18'
},
{
Id: 'wxyz0',
CurrentRow: 0,
ReportTime: '2022-07-19T00:00:00+00:00',
ExitTime: null,
DateField: '2022-07-19'
},
{
Id: 'wxyz1',
CurrentRow: 1,
ReportTime: '2022-07-19T00:00:00+00:00',
ExitTime: null,
DateField: '2022-07-19'
}
]
this is the code I came up with:
var tempRow = 0;
var tempDate = ''
YOUR_ARRAY
.sort((a, b) => (a.ReportTime > b.ReportTime) ? 1 : ((b.ReportTime > a.ReportTime) ? -1 : 0))
.forEach((row, i) => {
if (row.DateField != tempDate) {
tempDate = row.DateField
tempRow = 0
}
row.CurrentRow = tempRow
tempRow++
})

Sort an object by each value in a sub object

I'm trying to sort an object that is being used to display standings in a racing league. I need to be able to sort the drivers by not points but past finishing positions. If drivers end up on the same number of points then previous positions will be looked at starting at 1st place, going down to the last place which is dependant on how many drivers are in the league. The object which has all the drivers in looks something like this:
var standings = [{
driver: "Bob",
points: 45,
positions: {
0: 1,
1: 0,
2: 1,
3: 2,
4: 0
}
}, {
driver: "Mandy",
points: 17,
positions: {
0: 0,
1: 2,
2: 4,
3: 0,
4: 1
}
}, {
driver: "Robert",
points: 24,
positions: {
0: 0,
1: 1,
2: 5,
3: 3,
4: 0
}
}];
The positions object is number of times they've finished in a particular position, the key indicating the position so key 0 = 1st Place, key 1 = 2nd Place.
The number of key->values in the positions object will vary with the number of drivers in a league.
What I've been trying to do is work out how I can use underscore _.sortby to sort it first by the lowest position, working it's way up to 1st and then finally by the points but I can't seem to find a way to do this - running a loop which runs the sortby function on the object for every item in the positions object doesn't seem to work - it seems to just reset.
My initial attempt that doesn't seem to work is:
var driverCount = 3;
for (i = 0; i < driverCount; i++) {
standings = _.sortBy(standings, 'positions['+i+']').reverse();
}
standings = _.sortBy(standings, 'points').reverse();
Any ideas?
Change your object to:
var standings = [{
driver: "Bob",
points: 45,
positions: [
{key:0, valeu:1},
{key:1, valeu:0},
{key:2, valeu:1},
{key:3, valeu:2},
{key:4, valeu:0}
]
}, {
driver: "Mandy",
points: 17,
positions: [
{key:0, valeu:0},
{key:1, valeu:2},
{key:2, valeu:4},
{key:3, valeu:0},
{key:4, valeu:1}
]
}, {
driver: "Robert",
points: 24,
positions:[
{key:0, valeu:0},
{key:1, valeu:1},
{key:2, valeu:5},
{key:3, valeu:3},
{key:4, valeu:0}
]
}];
than use sort function to sort the positions and standings:
for (i = 0; i < standings.length; i++) {
standings[i].positions = standings[i].positions.sort(()=>{
if (a.value == b.value)
return 0;
if (a.value > b.value)
return -1;
else
return 1;
})
}
than sort the rest of the array:
standings.sort((a,b)=>{
if (a.points == b.points)
return 0;
if (a.points > b.points)
return -1;
else
return 1;
});
Didn't test the code, but you understand the idea
You have a composite sorting function.
I would use something like:
_sortBy(standings, (o) => o.points+Math.min(... _.pluck(o.positions, 'value')))); // wtach out your key is missspelled valeu

To group of array of objects by its id value

I have a group of array of objects in which that object property has value with ID number. I am successfully group it with that ID, however I am doing it by hardcode, not dynamically.
var objBuyUser = response.newIdUserPul[i].arrayUserHistoryBuy;
for (var y = 0; y < objBuyUser.length; y++) {
if(objBuyUser[y].product_id == 1) {
var doesIdExist = vm.pulBms.filter(function(v) {
return v.userid === response.newIdUserPul[i].id;
});
if(doesIdExist.length > 0) {
//do nothhing
} else {
vm.pulBms.push({
userid:response.newIdUserPul[i].id,
buyAct: objBuyUser
});
}
}
objBuyUser[y].product_id == 1 is what will different them each other. As long as this time we only have three ID number 1, 2, 3, I just copied the same code by changing the id manually. So, anybody can help to make it dynamically?
(**)SO: actually we have the list of product: 1, 2, 3
In the backend, I have process a unique user with its history buy, assign by response.newIdUserPul[i]. And the arrayUserHistoryBuy is the array of object detailing their product history buying from the range of the date, which in the object can consiste the date, quantity, and the product_id which need to be group here (reffer to -> **). In this case, knowing that each user can buy different product in the range of date, we still group it by product since the product is exist in the history of buying.
So the output could be similar like this:
ProductID1 :
{
User: 123
ProductBuyHistory :
{
Date: 3-10-10
ProductID : 2,
Quantity: 10
},
{
Date: 4-10-10
ProductID : 1,
Quantity: 10
},
},
{
User: 124
ProductBuyHistory :
{
Date: 3-10-10
ProductID : 3,
Quantity: 10
},
{
Date: 4-10-10
ProductID : 1,
Quantity: 10
},
},
SO on for productId 2 and 3

Trying to create a trending formula based on certain conditions

I have five articles with these initial properties:
const articles = [
{ id: 1, views: 92, likes: 0, shares: 2, trendingValue: ? },
{ id: 2, views: 14, likes: 2, shares: 1, trendingValue: ? },
{ id: 3, views: 39, likes: 3, shares: 1, trendingValue: ? },
{ id: 4, views: 87, likes: 0, shares: 1, trendingValue: ? },
{ id: 5, views: 8, likes: 1, shares: 0, trendingValue: ? }
];
I also have a global stats object that should be automatically updated once an article gets new views, likes or shares (or once a week):
const stats = {
totalArticles: 5,
totalViews: 240,
totalLikes: 6,
totalShares: 5,
trendingCriteria: 0
};
So far, I believe there is some sort of formula that can be done with articles' trendingValue and stats' trendingCriteria. Basically the articles that are "trending" need to have an equal or higher number than the criteria. Meaning that whenever an article gets a new view, share or like, trendingValue has to be updated in regards to it's percentage of views, likes and shares, by the global stats' counterparts.
An example (which doesn't exactly work) is:
A user views article 1.
This formula runs for the article to create its trendingValue:
const article = articles[0]; // Article with id 1
article.views++; // Increment the views count
stats.totalViews++ // Increment the total views count
let percentSum = (
(article.views / stats.totalViews) + // = 0.3833
(article.likes / stats.totalLikes) + // = 0
(article.shares / stats.totalShares) // = 0.4
); // = 0.7833
// The trendingValue needs to be a higher value of trendingCriteria
// before refreshing trendingCriteria.
article.trendingValue = (stats.trendingCriteria +
(percentSum / stats.trendingCriteria)
);
Next, trendingCriteria should be refreshed in regards to the updated article. The underlying logic is; if the new trendingCriteria is higher than the article's trendingValue, the article should no longer be "trending".
The third step is where I'm stuck. How do I create this value? Can this value be update for every single new view, like and share? Or do I have to update the value once a week or so?
Update
Thanks for all responses. Unfortunately I could not make any use of them since I'm yet confused what to do with the proposed solutions.
Anyhow, I tried another solution that makes use of an epoch timestamp and the average views, likes and shares. Not sure if it works in practice, so if anyone can confirm I'd be grateful.
function refreshArticleAtIndex(index, props) {
const data = articles[index];
// Increment props
if(props.view) { data.views++; stats.views++; }
else if(props.like) { data.likes++; stats.likes++; }
else if(props.share) { data.shares++; stats.shares++; }
// Refresh trendingRate
data.trendingRate = (() => {
const calcViews = data.views / stats.views;
const calcLikes = data.likes / stats.likes;
const calcShares = data.shares / stats.shares;
let value = Date.now() * (
(isFinite(calcViews) ? calcViews : 0) +
(isFinite(calcLikes) ? calcLikes : 0) +
(isFinite(calcShares) ? calcShares : 0)
);
return Math.round(value);
})();
}
function logArticles() {
const arr = articles.map(article => article);
arr.sort((a, b) => a.trendingRate > b.trendingRate ? -1 : 1);
arr.forEach(a => console.log(a.id +" |", a.trendingRate));
console.log("----------");
}
const stats = { views: 239, likes: 6, shares: 5 };
const articles = [
{ id: 1, views: 91, likes: 0, shares: 2, trendingRate: 0 },
{ id: 2, views: 14, likes: 2, shares: 1, trendingRate: 0 },
{ id: 3, views: 39, likes: 3, shares: 1, trendingRate: 0 },
{ id: 4, views: 87, likes: 0, shares: 1, trendingRate: 0 },
{ id: 5, views: 8, likes: 1, shares: 0, trendingRate: 0 }
];
console.log("ID | trendingRate");
// ================================================
// Add 1 view to article 1
refreshArticleAtIndex(0, { view: true });
// Add nothing to below articles, but refresh their trendingRate
refreshArticleAtIndex(1, {});
refreshArticleAtIndex(2, {});
refreshArticleAtIndex(3, {});
refreshArticleAtIndex(4, {});
logArticles();
// Add 1 like to article 1
refreshArticleAtIndex(0, { like: true });
logArticles();
The first log will show the correct order based on a combination of views, likes and shares for each article. Next, article 1 gets a like, which bumps it to the most trending article.
Question is if this is a working solution?
Trending probably should mean something like "top n% of activity" or "top n articles by activity".
Towards this end, you could simply save the trendingValue to an array like: { article: articleId, trendingValue: trendingValue}
Then when you go to find the most trending articles you would:
let cnt = trendingValues.length * myLimit
let i = 0
let trending = trendingValues.sort((a,b) => a.trendingValue > b.trendingValue).filter(() => i++ < cnt)
To use your language, trendingCriteria could be set to some minimum based on the set of articles. From there it could be fine tuned to ensure a certain minimum activity (as the average article age starts to grow).

Loop and Combine Time Ranges in an Array

I am trying to read through an array of objects (that are start/end times) and combine two (or more) of those times if they are back to back.
ie. the first objects end time is the same as the next objects start time. If they are, combine them. Then check the newly combined objects end time with the next object in the array
Here is a simplified array of times:
var times = [
{
start: 1,
end: 2
},{
start: 2,
end: 3
},{
start: 4,
end: 5
},{
start: 6,
end: 7
},
]
I would like that (or have a diff Array) to output like the below:
var newTimes = [
{
start: 1,
end: 3
},{
start: 4,
end: 5
},{
start: 6,
end: 7
},
]
It gets trickier if there are 3 times in a row.
var threeTime = [
{
start: 1,
end: 2
},{
start: 2,
end: 3
},{
start: 3,
end: 5
},{
start: 6,
end: 7
},
]
The above should turn into:
var newThreeTimes = [
{
start: 1,
end: 5
},{
start: 6,
end: 7
},
]
The original array of times will always be sorted from oldest (smallest start time) to newest (largest start time). The output does not need to be in any specific order. All time objects will be moment times.
Can someone help me solve this?
This is the code i have come up with
function mergeArr(arr) {
// Sort the array in descending order
arr.sort(function(a, b) {
return b.start - a.start;
});
// Traverse from the top as you will need to remove the elements
// Merge the elements based on start of one and end of the previous
for (var i = arr.length - 1; i > 0; i--) {
if (arr[i].end == arr[i - 1].start) {
arr[i].end = arr[i - 1].end;
arr.splice(i - 1, 1);
}
}
// Sort it again in reverse order.
return arr.sort(function(a, b) {
return a.start - b.start;
});
}
Comments are making the code self explanatory.
Working Fiddle

Categories