"Segmentize" collection with lodash

209 Views Asked by At
  • I have a collection col1

    var col1 = [1, 8, 9, 10, 2, 54, 7];
    
  • I have another collection col2

    var col2 = [1, 8, 23, 9, 46, 10, 2, 54, 78, 7]
    

    ...that I know it contains every element of col1, plus some other elements

  • I want to obtain this :

    var col3 = [
       [1, 8],
       [9],
       [10, 2, 54],
       [7]
    ]
    

    col1 "splitted", "segmentized" by col2

I'd like to use lodash functions for conciseness, but if someone brings an answer as vanilla JS, I'll accept the answer, and traduct it to lodash as an edit.

NB: I use ints for readability on SO, but my real collection contains objects.
NB2: each element is unique in both collections
NB3: elements that are common to both collections are in the same order

1

There are 1 best solutions below

12
On BEST ANSWER

I think a plain Javascript algorithm will be shorter, faster, and easier to understand here:

var l = [],
    col3 = [l],
    i = 0;
for (var j=0; j<col2.length; j++)
    if (col1[i] == col2[j])
        l.push(col1[i++]);
    else
        col3.push(l = []);

Same thing, less concise, using a lodash loop:

var col1Pointer = 0;
var segment = [];
var col3 = [];
col3.push(segment);

_.foreach(col2, function(col2Item) {
  var col1Item = col1[col1Pointer];
  if (col1Item == col2Item) {
    col1Pointer++;
    segment.push(col1Item);
  } else {
    segment = [];
    col3.push(segment);
  }
});

I can't think of a proper pure lodash way - there just is no appropriate method. But we could write one ourselves:

_.mixin({
    splitOn: function(arr, callback, thisArg) {
        if (!arr.length) return [];
        callback = _.callback(callbac, thisArg);
        var seg = [],
            res = [seg];
        for (var i=0; i<arr.length; i++)
            if (callback(arr[i], i, arr))
                res.push(seg = [])
            else
                seg.push(arr[i]);
        return res;
    }
});

and then use it like

var col3 = _.splitOn(col2, _.ary(_.partial(_.includes, col1), 1));