How do I retain the key name in the result using a lodash .map()?

Viewed 120
log(_.map(businessOpenSlots, weekday => {
        return _.spread(_.union)(_.map(weekday, slot => {
           return this.getTimeStops(slot.open, slot.close);
        }))
    } ))

This is code above is printing below. However, instead of 0..4, I want to key to be weekday.

Not sure how to best achieve this.

enter image description here

the businessOpenSlots data is below

{
   "friday":[
      {
         "open":"0900",
         "close":"1700"
      }
   ]"monday":[
      {
         "open":"0800",
         "close":"1530"
      },
      {
         "open":"1730",
         "close":"1930"
      }
   ]"thursday":[
      {
         "open":"0900",
         "close":"1700"
      }
   ]"tuesday":[
      {
         "open":"24hrs",
         "close":"24hrs"
      }
   ]"wednesday":[
      {
         "open":"0900",
         "close":"1700"
      }
   ]
}
2 Answers

Found the solution myself and posting it here for the community.

I just had to use _.mapValues() from Lodash.

let availableSlots = _.mapValues(businessOpenSlots, function(slots, weekday) {
       return _.spread(_.union)(_.map(slots, slot => {
          return vm.getTimeStops(slot.open, slot.close);
       }))
    });
log(availableSlots)

It returns the following, just as I wanted.

enter image description here

You can also do this relatively simply with vanilla JS. Here's one version:

const hoursToTimeStops = businessOpenSlots =>
  Object .fromEntries (
    Object .entries (businessOpenSlots) .map (([d, h]) => [d, h .flatMap (vm .getTimeStops)])
  )

const businessOpenSlots = {monday: [{open: "0800", close: "1530"}, {open: "1730", close: "1930"}], tuesday: [{open: "24hrs", close: "24hrs"}], wednesday: [{open: "0900", close: "1700"}], thursday: [{open: "0900", close: "1700"}], friday: [{open: "0900", close: "1700"}]}

console .log (hoursToTimeStops (businessOpenSlots))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script> // Dummy implementation for `vm`.
const every15mins = (sh, sm, eh, em) => sh * 60 + sm > eh * 60 + em ? [] : [`${String(sh).padStart(2, '0')}:${String(sm).padStart(2, '0')}`, ...every15mins(sh + (sm >= 45 ? 1 : 0), (sm + 15) % 60, eh, em)]
const vm = {getTimeStops:  ({open, close}) => open === '24hrs' ? ["00:00"] : every15mins(Number(open.slice(0, 2)), Number(open.slice(2, 4)), Number(close.slice(0, 2)), Number(close.slice(2, 4)))}
</script>

The process of calling entries, mapping the results, then calling fromEntries is nicely encapsulated by lodash's mapValues (or Ramda's map.) But the remainder of this seems simpler than your lodash version.

However, I believe you should be able to simplify that version quite a bit. I'm much more familiar with Ramda (disclaimer: I'm one of its authors), and I know that in Ramda, we could simply write:

const hoursToTimeStops = map (chain (vm.getTimeStops))

and I'm guessing you could get something similar using lodash's mapValues in place of map and its flatMap in place of chain. (It probably wouldn't be quite as elegant unless you used Lodash FP, but it wouldn't be that far off.)

Related