Grouping, merging and mapping with a timetable I want to create a "timetable" for some shop. It should look like, "days - hours".

I get response from the server in this way:

var array = [{
  days : ["Mo", "Tu", "We", "Th", "Sa"],
  dayIndexes: [1,2,3,4, 6],
  time: "9am - 3pm"
}, {
  days : ["Mo", "Tu", "We", "Th", "Sa"],
  dayIndexes: [1,2,3,4,6],
  time: "5pm - 9pm"
}, {
  days : ["Fr", "Su"],
  dayIndexes: [5,7],
  time: "9am - 2pm"
}];


It is like one object contains days for which shop has the same work hours. Duplicates by property days can happen because it is how the server implement "breaks" for a shop.

I've added my working sample, which returns exactly what I need, but I think it can be made simpler.

jsFiddle





var array = [{
     days: ["Mo", "Tu", "We", "Th", "Sa"],
     dayIndexes: [1, 2, 3, 4, 6],
     time: "9am - 3pm"
 }, {
     days: ["Mo", "Tu", "We", "Th", "Sa"],
     dayIndexes: [1, 2, 3, 4, 6],
     time: "5pm - 9pm"
 }, {
     days: ["Fr", "Su"],
     dayIndexes: [5, 7],
     time: "9am - 2pm"
 }];
 var convertToRanges = function(arr) {
     console.log(arr);
     if (arr.length &gt; 0) {
         var ranges = [
                 [arr[0], arr[0]]
             ],
             lastIndex = 0;

         for (var i = 1; i &lt; arr.length; i++) {
             if (arr[i] - ranges[lastIndex][1] === 1) {
                 ranges[lastIndex][1] = arr[i];
             } else {
                 ranges[++lastIndex] = [arr[i], arr[i]];
             }
         }

         var res = ranges.map((item) =&gt; {
             if (item[0] !== item[item.length - 1]) {
                 return moment.weekdaysShort(item[0]) + '-' + moment.weekdaysShort(item[item.length - 1]);
             } else {
                 return moment.weekdaysShort(item[0]);
             }
         });
     } else {
         res = moment.weekdaysShort(arr[0]);
     }

     return res.join(', ');
 }

 var result = _(array)
     .groupBy('dayIndexes')
     .map(function(days) {
         return _.mergeWith.apply(_, [{}].concat(days).concat([
             function(obj, src, key) {
                 if (key === 'time' &amp;&amp; obj &amp;&amp; src) {
                     return [obj, src].join(', ');
                 }
             }
         ]));
     })
     .values()
     .value()
     .map(d =&gt; {
         d.days = convertToRanges(d.dayIndexes);
         return d;
     });

 console.log(result);
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.2/moment.min.js"&gt;&lt;/script&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"&gt;&lt;/script&gt;
A review mostly focusing on style:


Avoid calls to console.log in clean code (it's okay for debugging, but should be removed afterwards)
Try not to declare variables in for statements ( the variable is accessible to the whole function anyway). Try to declare variables on top
Your code could use more comments, especially this part which was hardest to parse/grok:

     if (arr[i] - ranges[lastIndex][1] === 1) {
         ranges[lastIndex][1] = arr[i];
     } else {
         ranges[++lastIndex] = [arr[i], arr[i]];
     }



Other than that there is not much wrong with the code, I tried to write it in a more elegant way, but found my attempts usually longer and not that much more elegant.