5

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']
0

4 Answers 4

5

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] || [];
            groups[key].push(a);
        });

        Object.keys(groups).forEach(function (k) {
            groups[k].sort().pop();
        });

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

console.log(result);

Sign up to request clarification or add additional context in comments.

Comments

4

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), []);
console.log(b);

Comments

4

Using JavaScript you can try the code below:

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) {            
    arr[k].sort();
    for (var i = 0; i < arr[k].length - 1; i++) {
        numbers[j] = arr[k][i];
        j++;                
    }
}

console.log(numbers);

2 Comments

That's the fastest approach!
it changes the order.
0

All the current solutions assume that the numbers will be XXXX-Y where Y is always a number between 0 and 9 (maybe it is the requirement, but it is not clear in the question). In this case, we are working with Strings, so 1234-15 will be lower than 1234-7. It is needed to sort the Arraysin a numeric way. If we use the next Array with the current solutions on the page, this will be the results:

var array = ["14670-20", "7851", "7851-2", "14670-10", "7851-1", "2234", "2235", "2235-1", "14670-7"];

// ["14670-20", "7851", "14670-10", "7851-1", "2235"]
// ["14670-10", "14670-20", "7851", "7851-1", "2235"]
// ["2235", "7851", "7851-1", "14670-10", "14670-20"]

The number 14670-7 has been dropped because, as String, it is bigger than 14670-10 and 14670-20.

Here you have a solution that orders the Array first, and next reduce the values to get the lower ones (this solution changes the order of the original Array)

var array = ["14670-20", "7851", "7851-2", "14670-10", "7851-1", "2234", "2235", "2235-1", "14670-7"];

function getFilteredArray (array) {
    var reg = /^(\d+)\-?(\d*)$/;	
    var current = "";
    var sort = function (a, b) {
        var ra = a.match(reg), rb = b.match(reg);
        if (ra[1] === rb[1]) { return (+ra[2]) - (+rb[2]); }
        return (+ra[1]) - (+rb[1]);
    }
    return array.sort(sort).reduce(function (bundle, item, index) {
        var number = item.split("-")[0];
        bundle.splice((current !== number) ? -1 : bundle.length, 1, item);
        current = number;
        return bundle;
    }, []).slice(0, -1); 
}

console.log( getFilteredArray(array) );

This another solution is a little longer but it keeps the order of the original Array:

var array = ["14670-20", "7851", "7851-2", "14670-10", "7851-1", "2234", "2235", "2235-1", "14670-7"];

function getFilteredArray (array) {
    var reg = /^(\d+)\-?(\d*)$/;
    var sort = function (a, b) {
        var ra = a.match(reg), rb = b.match(reg);
        if (ra[1] === rb[1]) { return (+ra[2]) - (+rb[2]); }
        return (+ra[1]) - (+rb[1]);
    }
    var objs = array.reduce(function (bundle, item) {
        var number = item.split("-")[0];
        bundle[number] = bundle[number] || [];
        bundle[number].push(item);
        return bundle;
    }, {});
    for (var prop in objs) {
        var last = objs[prop].sort(sort).pop();
        array.splice(array.indexOf(last), 1);
    }
    return array;  
}

console.log( getFilteredArray(array) );

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.