11

Say I have an array of integers in Javascript, that I would like to check if all of its values are in ascending order. What i want is to save the array key in another array in case the algorithm finds a value that is lower (or equal) not only comparing the immediate previous one, but also comparing any value that is before it. What I did was this:

arr = [], nonvalid = [];

for (var j = 1; j < arr.length; j++){
    if ( arr[j+1] <= arr[j] ){
        nonvalid.push(j);
    }
}

Obviously the above algorightm checks only for values that are lower comparing the one before it.

An array might contain values like these:

arr = 1, 2, 3, 10, 5, 11, 12, 2, 4, 25

The non valid values are the bold ones. If I run the above loop, it won't "catch" the second last one (4), because it's higher than its closest left brother, but not that high than its all left brothers.

EDIT:

Tried the following solutions and none return all the nonvalid values for this array except mine . :(

They returned the last two values correctedly, but not the second one. I don't understand why though.

[24398, 24397, 25004, 25177, 26302, 28036, 29312, 29635, 29829, 30476, 32595, 33732, 34995, 36047, 36363, 37310, 38022, 38882, 40746, 41212, 42846, 43588, 44029, 44595, 44846, 45727, 46041, 47293, 48002, 48930, 49858, 51184, 51560, 53895, 54247, 54614, 55713, 56813, 57282, 57480, 57875, 58073, 58403, 60321, 61469, 62051, 62310, 62634, 63217, 64505, 65413, 65677, 65940, 66203, 66572, 67957, 68796, 68964, 69098, 69233, 69435, 69759, 71496, 72577, 72823, 73007, 73252, 73743, 73866, 76405, 77037, 77416, 77669, 79691, 80885, 81339, 81794, 82067, 82431, 83244, 84861, 86836, 88632, 89877, 90296, 91049, 91885, 92351, 92614, 93141, 93733, 93930, 94531, 95206, 95882, 96895, 97732, 97973, 99261, 99422, 99583, 100332, 100599, 101666, 102066, 102600, 103504, 104432, 105174, 107216, 109085, 110181, 110679, 111177, 111988, 112553, 113005, 113457, 600, 600]

Ricardus
  • 739
  • 2
  • 8
  • 15

9 Answers9

10

One other very nice functional way of doing this could be;

var isAscending = a => a.slice(1)
                        .map((e,i) => e > a[i])
                        .every(x => x);
                        
console.log(isAscending([1,2,3,4]));
console.log(isAscending([1,2,5,4]));

Nice code but there are redundancies in it. We can further simplify by consolidating .map() and .every() into one.

var isAscending = a => a.slice(1)
                        .every((e,i) => e > a[i]);
                        
console.log(isAscending([1,2,3,4]));
console.log(isAscending([1,2,5,4]));
Redu
  • 25,060
  • 6
  • 56
  • 76
9

Keep track of the largest value you have seen (see the fiddle):

function find_invalid_numbers(arr) {
    var nonvalid, i, max;

    nonvalid = [];

    if (arr.length !== 0) {
        max = arr[0];

        for (i = 1; i < arr.length; ++i) {
            if (arr[i] < max) {
                nonvalid.push(arr[i]);
            } else {
                max = arr[i];
            }
        }
    }

    return nonvalid;
}
cdhowie
  • 158,093
  • 24
  • 286
  • 300
4

Why not compare with the last known good number?

var arr = [1, 2, 3, 10, 5, 11, 12, 2, 4, 25],
    nonvalid = [],
    lastGoodValue = 0;

for (var j = 1; j < arr.length; j++) {
    if (j && arr[j] <= lastGoodValue) {
        //if not the first number and is less than the last good value
        nonvalid.push(arr[j]);
    } else {
        //if first number or a good value
        lastGoodValue = arr[j];
    }
}

console.log(arr, nonvalid)
Joseph
  • 117,725
  • 30
  • 181
  • 234
4

When you find an element out of order, look at the next elements until they are no longer out of order relative to the element before the out of order one.

Add the out of order elements to the second array and continue from the new in order element.

var outs= [], L= A.length, i= 0, prev;
while(i<L){
    prev= A[i]; 
    while(A[++i]<prev) outs.push(i);
}
alert(outs)
kennebec
  • 102,654
  • 32
  • 106
  • 127
  • Wow! A sophisticated and a laconic one :) Works like a charm. And it seems to be less demanding than other solutions. – Ricardus Apr 29 '13 at 20:13
1

DEMO

var arr = [24398, 24397, 25004, 25177, 26302, 28036, 29312, 29635, 29829, 30476, 32595, 33732, 34995, 36047, 36363, 37310, 38022, 38882, 40746, 41212, 42846, 43588, 44029, 44595, 44846, 45727, 46041, 47293, 48002, 48930, 49858, 51184, 51560, 53895, 54247, 54614, 55713, 56813, 57282, 57480, 57875, 58073, 58403, 60321, 61469, 62051, 62310, 62634, 63217, 64505, 65413, 65677, 65940, 66203, 66572, 67957, 68796, 68964, 69098, 69233, 69435, 69759, 71496, 72577, 72823, 73007, 73252, 73743, 73866, 76405, 77037, 77416, 77669, 79691, 80885, 81339, 81794, 82067, 82431, 83244, 84861, 86836, 88632, 89877, 90296, 91049, 91885, 92351, 92614, 93141, 93733, 93930, 94531, 95206, 95882, 96895, 97732, 97973, 99261, 99422, 99583, 100332, 100599, 101666, 102066, 102600, 103504, 104432, 105174, 107216, 109085, 110181, 110679, 111177, 111988, 112553, 113005, 113457, 600, 600],
    nonvalid = [],
    max = arr[0];

for(var j=0; j<arr.length; j++){
    var test= arr[j+1]<=max ? nonvalid.push(arr[j+1]) : max=arr[j];
}

alert(nonvalid); // 24397, 600, 600
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
1

a simple functional way to do it inline without loops or variables:

arr.filter(function(a,b,c){
  return  Math.max.apply(Math, c.slice(0,b)) > a ;
});
dandavis
  • 16,370
  • 5
  • 40
  • 36
1

You can use map with this example:

const ascendingArray = [1,2,3,4,5,6,7];
const descendingArray = [1,2,3,7,5,6,4]

const isAscending = array => array.map((a, i) => a > array[i + 1]).indexOf(true) === -1

console.log(isAscending(descendingArray)); // should be false
console.log(isAscending(ascendingArray)); // should be true

Or, you can use filter with this example:

const ascendingArray = [1,2,3,4,5,6,7];
const descendingArray = [1,2,3,7,5,6,4]

const isAscending = array => array.filter((a, i) => a > array[i + 1]).length === 0;

console.log(isAscending(ascendingArray)); // should be true
console.log(isAscending(descendingArray)); // should be false
Titus Sutio Fanpula
  • 3,467
  • 4
  • 14
  • 33
0

Copy the array first, remove any element that is not in order with array.splice(index, 1), and continue. That way, any element must by greater than the one right before it, but the one right before it will always be the max.

dave
  • 62,300
  • 5
  • 72
  • 93
0

Answering my own question after taking your advices I tried the following algorightm. It seems to do its job but its a bit overkill.

for (var i = 0; i < arr.length; i++){

for (var j = 1; j < arr.length; j++){

    if ( arr[j] > 0 && arr[i] > 0 && j != i ){

        if ( arr[j] <= arr[i] && j > i ){

            if ( jQuery.inArray(j, nonvalid) == - 1) nonvalid.push(j);
        }
    }
} }
Ricardus
  • 739
  • 2
  • 8
  • 15