enapupe enapupe - 8 days ago 5
Javascript Question

immutable.js filter and mutate (remove) found entries

I have two loops, one for each day of the month, other with all events for this month. Let's say I have 100 000 events.
I'm looking for a way to remove events from the main events

List
once they were "consumed".

The code is something like:

const calendarRange = [{initialDate}, {initialDate}, {initialDate}, {initialDate}, ...] // say we have 30 dates, one for each day
const events = fromJS([{initialDate}, {initialDate}, {initialDate}, ...]) // let's say we have 100 000
calendarRange.map((day) => {
const dayEvents = events.filter((event) => day.get('initialDate').isSame(event.get('initialDate'), 'day')) // we get all events for each day
doSomeThingWithDays(dayEvents)
// how could I subtract `dayEvents` from `events` in a way
// the next celandarRange iteration we have less events to filter?
// the order of the first loop must be preserved (because it's from day 1 to day 3{01}])
}


With lodash I could just do something like:

calendarRange.map((day) => {
const dayEvents = events.filter((event) => day.get('initialDate').isSame(event.get('initialDate'), 'day')) // we get all events for each day
doSomeThingWithDays(dayEvents)
pullAllWith(events, dayEvents, (a, b) => a === b)
}


How to accomplish the same optimization with immutablejs? I'm not really expecting a solution for my way of iterating the list, but for a smart way of reducing the events
List
in a way it get smaller and smaller..

Answer

You can try a Map with events split into bins - based on your example, you bin based on dates - you can lookup a bin, process it as a batch and remove it O(1). Immutable maps are fairly inexpensive, and fare much better than iterating over lists. You can incur the cost of a one time binning, but amortize it over O(1) lookups.

Something like this perhaps:

eventbins = OrderedMap(events.groupBy(evt => evt.get('initialDate').dayOfYear() /* or whatever selector */)) 

function iter(list, bins) { 
 if(list.isEmpty()) 
   return
 day = list.first()
 dayEvents = bins.get(day.dayOfYear())
 doSomeThingWithDays(dayEvents)
 iter(list.shift(), bins.delete(day))
}

iter(rangeOfDays, eventbins)