2

Okay, so I've been working on a sort function for my application, and I've gotten stuck.

Here's my fiddle.

To explain briefly, this code starts with an array of strings, serials, and an empty array, displaySerials:

var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"]; var displaySerials = []; 

The aim of these functions is to output displaySerials as an array of objects with two properties: beginSerial and endSerial. The way that this is intended to work is that the function loops through the array, and tries to set each compatible string in a range with each other, and then from that range create the object where beginSerial is the lowest serial number in range and endSerial is the highest in range.

To clarify, all serials in a contiguous range will have the same prefix. Once that prefix is established then the strings are broken apart from the prefix and compared and sorted numerically.

So based on that, the desired output from the array serials would be:

displaySerials = [ { beginSerial: "BHU-008", endSerial: "BHU-011" }, { beginSerial: "BHU-000", endSerial: "BHU-002" }, { beginSerial: "TYU-969", endSerial: "TYU-970" } ] 

I've got it mostly working on my jsfiddle, the only problem is that the function is pushing one duplicate object into the array, and I'm not sure how it is managing to pass my checks.

Any help would be greatly appreciated.

5
  • How is the compatibility between serials determined?
    – aaaidan
    CommentedOct 1, 2015 at 21:10
  • Looks like he's seeking contiguous numerical blocks that have the same prefix. I.e., for BHU, you have 8, 9, 10, and 11 contiguous, which is why that particular range has beginSerial 8 and endSerial 11. I didn't understand at first either.
    – Marc
    CommentedOct 1, 2015 at 21:11
  • Marc is correct on that one. All serials in range will have the same prefix and once that prefix is established (in the same context as the above example, "BHU-0") then the strings are broken apart from the prefix and compared and sorted numerically.CommentedOct 1, 2015 at 21:18
  • Does the order of output objects matter?
    – Touffy
    CommentedOct 1, 2015 at 21:26
  • @Touffy No, the output order does not matter.CommentedOct 1, 2015 at 21:28

5 Answers 5

1

Marc's solution is correct, but I couldn't help thinking it was too much code. This is doing exactly the same thing, starting with sort(), but then using reduce() for a more elegant look.

var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"] serials.sort() var first = serials.shift() var ranges = [{begin: first, end: first}] serials.reduce(mergeRange, ranges[0]) console.log(ranges) // the expected result // and this is the reduce callback: function mergeRange(lastRange, s) { var parts = s.split(/-/) var lastParts = lastRange.end.split(/-/) if (parts[0] === lastParts[0] && parts[1]-1 === +lastParts[1]) { lastRange.end = s return lastRange } else { var newRange = {begin: s, end: s} ranges.push(newRange) return newRange } } 

I've got a feeling that it's possible to do it without sorting, by recursively merging the results obtained over small pieces of the array (compare elements two by two, then merge results two by two, and so on until you have a single result array). The code wouldn't look terribly nice, but it would scale better and could be done in parallel.

    1

    Nothing too sophisticated here, but it should do the trick. Note that I'm sorting the array from the get-go so I can reliably iterate over it.

    Fiddle is here: http://jsfiddle.net/qyys9vw1/

    var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"]; var myNewObjectArray = []; var sortedSerials = serials.sort(); //seed the object var myObject = {}; var previous = sortedSerials[0]; var previousPrefix = previous.split("-")[0]; var previousValue = previous.split("-")[1]; myObject.beginSerial = previous; myObject.endSerial = previous; //iterate watching for breaks in the sequence for (var i=1; i < sortedSerials.length; i++) { var current = sortedSerials[i]; console.log(current); var currentPrefix = current.split("-")[0]; var currentValue = current.split("-")[1]; if (currentPrefix === previousPrefix && parseInt(currentValue) === parseInt(previousValue)+1) { //sequential value found, so update the endSerial with it myObject.endSerial = current; previous = current; previousPrefix = currentPrefix; previousValue = currentValue; } else { //sequence broken; push the object console.log(currentPrefix, previousPrefix, parseInt(currentValue), parseInt(previousValue)+1); myNewObjectArray.push(myObject); //re-seed a new object previous = current; previousPrefix = currentPrefix; previousValue = currentValue; myObject = {}; myObject.beginSerial = current; myObject.endSerial = current; } } myNewObjectArray.push(myObject); //one final push console.log(myNewObjectArray); 
    2
    • This works! The only thing about this solution that doesn't work entirely for my purposes is the use of the .split("-") function. It works here but I can't guarantee that all the serial numbers in the application will have this structure to them. I should have specified that better in my initial post.CommentedOct 1, 2015 at 22:17
    • 1
      Okay... so how might they differ? As long as there's a hyphen to split the serial from the prefix, this will work.
      – Marc
      CommentedOct 1, 2015 at 22:21
    0

    I would use underscore.js for this

    var bSerialExists = _.findWhere(displaySerials, { beginSerial: displaySettings.beginSerial }); var eSerialExists = _.findWhere(displaySerials, { endSerial: displaySettings.endSerial }); if (!bSerialExists && !eSerialExists) displaySerials.push(displaySettings); 
      0

      I ended up solving my own problem because I was much closer than I thought I was. I included a final sort to get rid of duplicate objects after the initial sort was finished.

      var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"]; var displaySerials = []; var mapSerialsForDisplay = function () { var tempArray = serials; displaySerials = []; for (var i = 0; i < tempArray.length; i++) { // compare current member to all other members for similarity var currentSerial = tempArray[i]; var range = [currentSerial]; var displaySettings = { beginSerial: currentSerial, endSerial: "" } for (var j = 0; j < tempArray.length; j++) { if (i === j) { continue; } else { var stringInCommon = ""; var comparingSerial = tempArray[j]; for (var n = 0; n < currentSerial.length; n++) { if (currentSerial[n] === comparingSerial[n]) { stringInCommon += currentSerial[n]; continue; } else { var currentRemaining = currentSerial.replace(stringInCommon, ""); var comparingRemaining = comparingSerial.replace(stringInCommon, ""); if (!isNaN(currentRemaining) && !isNaN(comparingRemaining) && stringInCommon !== "") { range = compareAndAddToRange(comparingSerial, stringInCommon, range); displaySettings.beginSerial = range[0]; displaySettings.endSerial = range[range.length - 1]; var existsAlready = false; for (var l = 0; l < displaySerials.length; l++) { if (displaySerials[l].beginSerial == displaySettings.beginSerial || displaySerials[l].endSerial == displaySettings.endSerial) { existsAlready = true; } } if (!existsAlready) { displaySerials.push(displaySettings); } } } } } } } for (var i = 0; i < displaySerials.length; i++) { for (var j = 0; j < displaySerials.length; j++) { if (i === j) { continue; } else { if (displaySerials[i].beginSerial === displaySerials[j].beginSerial && displaySerials[i].endSerial === displaySerials[j].endSerial) { displaySerials.splice(j, 1); } } } } return displaySerials; } var compareAndAddToRange = function (candidate, commonString, arr) { var tempArray = []; for (var i = 0; i < arr.length; i++) { tempArray.push({ value: arr[i], number: parseInt(arr[i].replace(commonString, "")) }); } tempArray.sort(function(a, b) { return (a.number > b.number) ? 1 : ((b.number > a.number) ? -1 : 0); }); var newSerial = { value: candidate, number: candidate.replace(commonString, "") } if (tempArray.indexOf(newSerial) === -1) { if (tempArray[0].number - newSerial.number === 1) { tempArray.unshift(newSerial) } else if (newSerial.number - tempArray[tempArray.length - 1].number === 1) { tempArray.push(newSerial); } } for (var i = 0; i < tempArray.length; i++) { arr[i] = tempArray[i].value; } arr.sort(); return arr; } mapSerialsForDisplay(); console.log(displaySerials); 

      fiddle to see it work

        0

        Here's a function that does this in plain JavaScript.

        var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"]; function transformSerials(a) { var result = []; //store array for result var holder = {}; //create a temporary object //loop the input array and group by prefix a.forEach(function(val) { var parts = val.split('-'); var type = parts[0]; var int = parseInt(parts[1], 10); if (!holder[type]) holder[type] = { prefix : type, values : [] }; holder[type].values.push({ name : val, value : int }); }); //interate through the temp object and find continuous values for(var type in holder) { var last = null; var groupHolder = {}; //sort the values by integer var numbers = holder[type].values.sort(function(a,b) { return parseInt(a.value, 10) > parseInt(b.value, 10); }); numbers.forEach(function(value, index) { if (!groupHolder.beginSerial) groupHolder.beginSerial = value.name; if (!last || value.value === last + 1) { last = value.value; groupHolder.endSerial = value.name; if (index === numbers.length - 1) { result.push(groupHolder); } } else { result.push(groupHolder); groupHolder = {}; last = null; } }); } return result; } console.log(transformSerials(serials));
        <script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

        2
        • Pretty close, though one thing that is necessary is that if the serial numbers are not contiguous they should be output to a separate object. So because there is a numerical gap between BHU-002 and BHU-008 the output would need include an object for BHU-000 to BHU-002 and also BHU-008 to BHU-011.CommentedOct 1, 2015 at 21:56
        • Sorry I missed that. It is fixed in the updated answer.
          – Dave
          CommentedOct 1, 2015 at 22:37

        Start asking to get answers

        Find the answer to your question by asking.

        Ask question

        Explore related questions

        See similar questions with these tags.