[JS] Need help filtering an array of strings
New here? Learn about Bountify and follow @bountify to get notified of new bounties! x

I need to filter an array and I am totally drawing a blank on how to do so.

I need to filter out the largest numbers. A number can be deemed larger when the first number is XXXX and the second is XXXX-1, then the second number is larger. Or it can be deemed larger if the first number is XXXX-1 and the second is XXXX-2, then the second is largest.

In the case that the number has no version thats larger, in the example below lets look at '2234'. There is no 2234-1, so thus, 2234 is the largest of its kind and should be removed.

So given this array (of strings) as an example: [7851, 7851-2, 7851-1, 2234, 2235, 2235-1]

I would expect this result: [7851, 7851-1, 2235]

Is this being done in batches, or is there a constant stream of data? Also, where are you getting this format from?
slang800 over 2 years ago
This is done in one batch. Each number (7851, 7851-1, etc) are license numbers and version. For example. License Number: 0001 0001 has an addendum created, now its 0001-1. That addendum has an addendum created, now its 0001-2. I am trying to filter out the 'current' so in the example over, 0001-2 will be filtered out and removed. 0001 and 0001-1 will remain in the result. I hope this cleared some things up, thanks for the help on this!
jeffward01 over 2 years ago
awarded to clkwan

Crowdsource coding tasks.

2 Solutions

i propose three approaches to do that:

1 . You could group the items and sort it later, then pop the last and filter the original array with a look up for the saved value.

var array = ['7851', '7851-2', '7851-1', '2234', '2235', '2235-1'],
result = function (array) {
    var groups = Object.create(null);

    array.forEach(function (a) {
        var key = a.split('-')[0];
        groups[key] = groups[key] || [];

    Object.keys(groups).forEach(function (k) {

    return array.filter(function (a) {
        return groups[a.split('-')[0]].some(function (b) { return a === b; });


2 . the fastest approach but it changes the order

var numbers = ["7851", "7851-2", "7851-1", "2234", "2235", "2235-1"];
var arr = [];
for (var i = 0; i < numbers.length; i++)
    // The first part of the number defines the hash key
    var hash_key = numbers[i].split("-")[0];
    if (arr[hash_key] === undefined)
        arr[hash_key] = [];
    arr[hash_key][arr[hash_key].length] = numbers[i];

// sort each array - 
// then access all elements but the last and populate numbers array 
var numbers = [];
var j = 0;
for (var k in arr) {            

    for (var i = 0; i < arr[k].length - 1; i++) {
        numbers[j] = arr[k][i];


3 . A combination of reduce and map would do the job in one go:

let a = ["7851", "7851-2", "7851-1", "2234", "2235", "2235-1"];
let b = [...a.reduce((a, b) => {
  let s = b.split("-");
  a.set(s[0], (!a.has(s[0]) ? [(s[1] || 0)] : a.get(s[0]).concat((s[1] || 0))));
  return a;
}, new Map()).entries()].map(k => {
  k[1].sort((a, b) => b < a).pop();
  if (k[1].length === 0) return;
  return k[1].map(f => k[0] + (f > 0 ? "-" + f : ""))
}).filter(v => v).reduce((a, b) => a.concat(b), []);

you can use what ever you want that fit your choice ;) good luck ;)

Thanks for these 3 methods!! They are excellent! The first one does exactly what I need! You are AWESOME! I couldnt get the 2nd, and 3rd to work; but I know I can if I spent some time implementing it. The first one works and passes 110% I would love to award you the bounty, but the user above you (@philklc) completed the solution a few hours before you did Your solution is correct, I appreciate the effort and help! I will message you in the future for similar problems!
jeffward01 over 2 years ago
I posted this on reddit too, and another user came up with a solution as well. Totally different than yours. Your first one does the job great! I think yours may be more scalable to since it can do 1234-10, while the solution below, can only do one digit(1234-9). Here it is if your interested: https://repl.it/FwOb
jeffward01 over 2 years ago
great that this helped you, this is my email, you can contact me for featured help if you want: nicolastsue@gmail.com . Also, if you liked my solutions, you can tip me :p just kidding xD . Anyway, you have my email, email me for further help ;)
Chlegou over 2 years ago
Winning solution

//Array.prototype.diff = function(e) {
//  return this.filter(function(i) {return e.indexOf(i) < 0;});

function myArrayFilter(arr) {
  var numKnownVariations = [], largestNums = [];
  for (var i = 0; i < arr.length; i++) {
    var splitVal = arr[i].split('-');
    if (typeof numKnownVariations[splitVal[0]] === 'undefined') numKnownVariations[splitVal[0]] = [];
    if (splitVal.length == 2) numKnownVariations[splitVal[0]].push(splitVal[1]);
  for (key in numKnownVariations) {
    if (typeof numKnownVariations[key] === "object") {
        (numKnownVariations[key].length>0) ?
          : ""
  //return arr.diff(largestNums);
  return arr.filter(function(v){return largestNums.indexOf(v)<0});

var example = ["7851", "7851-2", "7851-1", "2234", "2235", "2235-1"];
You shouldn't be extending the global array prototype - that will give you shit performance and will cause conflicts on larger applications.
slang800 over 2 years ago
Thank you very much for the solution! You solved it fast and it passed all my tests! @slang800 is correct about that. In this case I dont think it will be a large factor, I dont use Array.prototypes anywhere else in the applicaiton. Also, the largest the list will be is perhaps 15 numbers total. In the example input you use 6. Thanks for the help! I posted this on reddit too, and another user came up with a solution as well. Totally different than yours. Here it is if your interested: https://repl.it/FwOb
jeffward01 over 2 years ago
Hi @jeffward01, yes @slang800 is correct about not extending global prototypes. I have updated the solution to have it no longer do that.
clkwan over 2 years ago
View Timeline