-
-
Save brittanydionigi/9818971 to your computer and use it in GitHub Desktop.
/* Some boys are playing a hockey game and they each play a certain number of shifts. */ | |
/* For simplicity, we'll say there are 15 different shifts in a game. */ | |
[ | |
{ | |
"player": "Joe", | |
"shifts": [ | |
{ "shift_start": 3, "shift_end": 5 }, // Joe started playing at shift #3, and stopped after shift #5 | |
{ "shift_start": 7, "shift_end": 11 } | |
] | |
}, | |
{ | |
"player": "Marc", | |
"shifts": [ | |
{ "shift_start": 1, "shift_end": 4 }, | |
{ "shift_start": 9, "shift_end": 13 } | |
] | |
}, | |
{ | |
"player": "John", | |
"shifts": [ | |
{ "shift_start": 4, "shift_end": 8 }, | |
{ "shift_start": 10, "shift_end": 12 } | |
] | |
} | |
] | |
/* We want to take all of Joe's shifts, and find out which shifts each player overlapped with him on. ie: */ | |
/* Marc played shifts: 3, 4, 9, 10, 11 with Joe */ | |
/* John played shifts: 4, 5, 7, 8, 10, 11 with Joe */ | |
/* How do we do it? */ | |
/* Data modeling can change slightly if need be. */ | |
My solution: http://jsfiddle.net/vBmY8/
Friendly twitter people solutions:
https://gist.github.com/benheb/fb42caaeba48b67021fc
Stephen - this is possible. The reason it's not set up like that now is because most of the time I really only need the start & end points of a shift. This is one rare exception where I need to get all the in-between-stuff. Also, the scale of this is going to be more like...20-40 shifts per player, about 40 players, and shifts between 0 and at least 3600, as opposed to 1-15.
Because I’m that guy when it comes to CoffeeScript (and Underscore):
player_data = […above list…]
players = {}
_.each player_data, (player) ->
shift_list = []
# Create a single Array with all of the shifts enumerated for that player.
_.each player.shifts, (shift) ->
shift_list.push([shift.shift_start..shift.shift_end]...)
players[player.player] = shift_list
console.log _.intersection(players['Joe'], players['Marc'])
console.log _.intersection(players['Joe'], players['Marc'], players['John'])
Edit: since I’m trying to be less obnoxious about CoffeeScript, a JS version (Underscore is pretty great):
player_data = […above list…]
var players = {};
// Map an enumerated list of shifts to each player name (likely will be
// ordered, but that doesn’t matter)
_.each(player_data, function(player){
var shift_list = _.map(player.shifts, function(shift){
// Add each shift as a full range.
return _.range(shift.shift_start, shift.shift_end + 1);
});
// The shift_list is a nested Array, so flatten it. As long as the starts
// and ends don't overlap, there won't be duplication (though doesn't
// matter for intersection).
players[player.player] = _.flatten(shift_list);
});
// _.intersection allows for any number of lists to be compared. Yay.
console.log(_.intersection(players['Joe'], players['Marc']));
// [ 3, 4, 9, 10, 11 ]
console.log(_.intersection(players['Joe'], players['Marc'], players['John']));
// [ 4, 10, 11 ]
Edit 2: oops, clarified player_data
Edit 3: comments (I’m stuck in a boring meeting pretending to take notes)
Oh gosh I don't know coffeescript. I don't even know how to write my player_data. UNEXPECTED IDENTIFIERS EVERYWHERE.
The first link you posted essentially does the same thing I was suggesting - except it creates the new data structure from your data structure. They just stores each range on object.[playerName]
and then loops through the other players and compares the _.intersection
. The second link might be a lot faster or efficient, although at a glance it's a lot trickier to read.
If your database can store the ranges on each player for you (e.g. storage space less of a concern) then you wouldn't have to perform the range production in your code. Maybe saving some performance there, I'm not a performance guru though so it might be negligible.
Also, if you do end up storing a range on each player but are typically only working with a start and end input, you could change the data to something like:
{
'player': 'Joe',
'shifts': [0,1,2],
'start': 0,
'end': 2
}
In which case writing updates you'd just need to make sure to replace the shifts
with a new range if start and end changed.
edit: TL;DR - if everyone ends up using _.intersection
on a range that they calculate, my point is why not just calculate the range once upon create or update, and then save the ops later if you allow lots of intersection calculations in your app
If the data modeling can change, and I hope I don't I come off snobby, why not just store each shift explicitly:
I'm sure at that point you're a
_
function or two away from finding out (something like aunion
with unique between players or something like that).Or, is the point to solve it with this structure and using your own tools (school, interview, production limitations on adding external libraries, etc)?