How to compare different indexes in array using Javascript array methods - javascript

I'm trying to solve the problem below but I'm stuck in knowing how to compare one index with another that's not consequently for example:
const arr = ["Juan", "Maria", "Maria", "Juan"]
In this case, comparing index 1 and 2 would be simple, but how can I pick index 0 and then compare it with each one of the others until it get to index 3 to be matched?.
Exercise
Input: USA, AUSTRALIA, AUSTRALIA, INDIA, FRANCE, USA
Print out the name of the Country and word "Bingo" if the element (Country name) is repeated and located one after another
Print out the name of the Country and word "Hooray" if the element (Country name) is repeated and located not consequently
Note: Use any Array method
Expected result: "Bingo Australia" "Hooray USA"
This is what I've tried.
Note that if I run it that way it would work but only because I'm accessing countries[index + 5].
How can I make the index to dynamically increases itself when the iteration finishes?
const countries = ['USA', 'Australia', 'Australia', 'France', 'India', 'USA'];
countries.forEach((value, index) => {
if (countries[index] === countries[index + 1]) {
console.log(`Bingo ${value}`);
} else if (countries[index] === countries[index + 5]) {
console.log(`Hooray ${value}`);
}
});

You can try something like this, it is not most efficient but it will solve your problem:
const countries = ['USA', 'Australia', 'Australia', 'France', 'India', 'USA'];
countries.forEach((value, index, arr) => {
arr.forEach((val, idx) => {
if (val === value && index < idx) {
if (idx === index + 1) console.log(`Bingo ${value}`);
else console.log(`Hooray ${value}`);
}
});
});

Solution with a lot of 'if' (just reduce iterations (loop count)
Wrote with purpose with for loop, in reality, it is same as a nested loop.
const c_arr = [1, 4, 5, 5, 6, 7, 4, 1];
let j = 0;
let full_count = 0; //count loops
for (let i = 0; i < c_arr.length; ++i) {
if (j === 0 & c_arr[i] === c_arr[i + 1]) { // condition j ==0 so it will go inside only in first loop
console.log('Bingo', c_arr[i])
}
// console.log("Test", c_arr[j]);
if (i + 2 < c_arr.length & c_arr[j] === c_arr[i + 2]) { // i+2 cond, to avoid to access elem. outside array
console.log('Hooray', c_arr[i + 2]);
c_arr[j] = null;
}
// All to reduce loop count
if (j > 0 & c_arr[j] === null) { // allneigbourgh elements are checked
i = j;
++j;
}
if (j > 0 & i === c_arr.length - 3) { // avoid empty loop, condition for Hooray is i+2
i = j;
++j;
}
if (i === c_arr.length - 1) { // on first loop increase j
i = j;
++j;
}
// to stop loop when J reaches arr :-2 element
if (j === c_arr.length - 2) {
i = c_arr.length;
}
++full_count;
}
console.log(full_count, " :loops count");

Related

Implement an algorithm to summarize the number of items within buckets of ranges

I am trying to write a function that takes an array of numbers (always ascendingly sorted) and an array of buckets where each bucket is a tuple (array of two items) that represents a range (no overlaps). Every adjacent tuple only diff by 1. For example, [[0, 59], [60, 90]]. And they are always sorted.
For example,
summarize( [0, 10, 60, 120],[[0, 59], [60, 90]]) gives us [2, 1] because within [0, 59] there are two elements 0 and 10 and between [60, 90] there is one element 60.
Here is my attempt:
function summarize(array, buckets) {
let i = 0
const results = Array.from({ length: buckets.length }, () => 0)
for (const item of array) {
if (item >= buckets[i][0] && item <= buckets[i][1]) results[i]++
else if (item > buckets[i][1] && i !== buckets.length - 1) {
if (item <= buckets[i + 1][0]) {
results[i + 1]++
i++
if (i === buckets.length) break
}
}
}
return results
}
The code seems to be working but it looks not clean and brittle. I wonder if there is another way to do it?
The time complexity should be dependent on two dimensions: the size of the first array (n), and the number of buckets (m). The best we can get is O(n+m), because certainly all values of the first array must be visited, and since the output has one entry per bucket, we must also do O(m) work to produce that output.
Your code is aiming for that time complexity, but it has an issue. For instance, the following call will not produce the correct result:
summarize([9], [[1, 3], [4, 6], [7, 9]])
The issue is that your code is not good at skipping several (more than one) bucket to find the place where a value should be bucketed. Concretely, both if conditions can be false, and then nothing happens with the currently iterated value -- it is not accounted for.
Since the output has the same size as the bucket list, we could consider mapping the bucket list to the output. Then the i index becomes an auxiliary index for the first array.
Here is how the code could look:
function summarize(array, buckets) {
let i = 0;
return buckets.map(([start, end]) => {
while (array[i] < start) i++;
let j = i;
while (array[i] <= end) i++;
return i - j;
});
}
// Example run
console.log(summarize([0, 10, 60, 120],[[0, 59], [60, 90]]));
Your code seems to rely on buckets being both non overlapping AND adjacent.
The code below only requires that each "bucket" array be in ascending order. As it is (with the "break" commented) it doesn't require the numbers to be in any order, and the buckets can overlap, etc.
HTH
function summarize(array, buckets) {
const results = new Array(buckets.length).fill(0);
for (i in array) {
for (j in buckets) {
if (array[i] >= buckets[j][0] && array[i] <= buckets[j][1]) {
results[j]++;
// break;
}
}
}
return results;
}
console.log(summarize([0, 10, 60, 120], [
[0, 59],
[60, 90]
]));
This doesn't require the input or buckets to be sorted and it allows the buckets to overlap:
summarize=(a,b)=>b.map(x=>a.filter(y=>y>=x[0]&&y<=x[1]).length)
Edit: The nisetama2 function in the following benchmark requires that the input and buckets are sorted and that the buckets do not overlap:
let nisetama=(a,b)=>b.map(x=>a.filter(y=>y>=x[0]&&y<=x[1]).length)
function nisetama2(a,b){
let min=b[0][0],max=b[0][1],n=0,out=Array(b.length).fill(0)
for(let i=0,l=a.length;i<l;i++){
let v=a[i]
while(v>max){if(n==b.length-1)return out;n++;min=b[n][0];max=b[n][1]}
if(v>=min)out[n]++
}
return out
}
function nistetama2_for_of(a,b){
let min=b[0][0],max=b[0][1],n=0,out=Array(b.length).fill(0)
for(let v of a){
while(v>max){if(n==b.length-1)return out;n++;min=b[n][0];max=b[n][1]}
if(v>=min)out[n]++
}
return out
}
function OP(array, buckets) {
let i = 0
const results = Array.from({ length: buckets.length }, () => 0)
for (const item of array) {
if (item >= buckets[i][0] && item <= buckets[i][1]) results[i]++
else if (item > buckets[i][1] && i !== buckets.length - 1) {
if (item <= buckets[i + 1][0]) {
results[i + 1]++
i++
if (i === buckets.length) break
}
}
}
return results
}
function WolfD(array, buckets) {
const results = new Array(buckets.length).fill(0);
for (i in array) {
for (j in buckets) {
if (array[i] >= buckets[j][0] && array[i] <= buckets[j][1]) {
results[j]++;
}
}
}
return results;
}
function WolfD_let(array, buckets) {
const results = new Array(buckets.length).fill(0);
for (let i in array) {
for (let j in buckets) {
if (array[i] >= buckets[j][0] && array[i] <= buckets[j][1]) {
results[j]++;
}
}
}
return results;
}
function trincot(array, buckets) {
let i = 0;
return buckets.map(([start, end]) => {
while (array[i] < start) i++;
let j = i;
while (array[i] <= end) i++;
return i - j;
});
}
let a=Array(1e4).fill().map((_,i)=>i)
let b=Array(1e2).fill().map((_,i)=>[i*100,(i+1)*100-1])
let opt=['nisetama','nisetama2','nisetama2_for_of','OP','WolfD','WolfD_let','trincot']
opt.sort(()=>Math.random()-.5)
for(let opti of opt){
let t1=process.hrtime.bigint()
eval(opti+'(a,b)')
let t2=process.hrtime.bigint()
console.log(t2-t1+' '+opti)
}
Here's the median time of a thousand runs in ms (updated to add trincot's function):
0.43 trincot
0.67 nisetama2
3.10 nisetama2_for_of
4.03 OP
12.66 nisetama
45.32 WolfD_let
201.55 WolfD
Wolf D.'s solution became about 4 times faster when I modified it to use block-scoped variables.
In order to reduce the effect of optimizations for running the same code multiple times, I ran the benchmark like for i in {0..999};do node temp.js;done instead of running each option a thousand times inside the script.

Check if an array is descending, ascending or not sorted?

I'm just beginning with programming using javascript and I need to practice some questions to get EXP with the logic of code build.
I got this question for homework but I can't make it work for some reason, even though it seems "logic" to me.
Check if an array is descending, ascending or not sorted using loops.
I'm just a noob so please try and help me figure this out as I only got to loops in my studies (:
this is the code I wrote:
var array = [1, 2, 3, 7 ];
var d = 0;
var c =0 ;
var b = 1;
var a = 0;
for (var i = 1; i <= array.length; i++)
{
if (array[c]<array[b] && a!== -1 ){
d = -1;
c =c+1;
b = b+1;
if(c==array.length){
console.log("asc");
break;
}else{
continue;
}
} else if (array[c]>array[b] && d!==-1 ){
a = -1;
d= d+1;
b = b+1;
if(i=array.length){
console.log("dsc");
break;
}else{continue;}
} else{
console.log("unsorted array");
break;
}
}
Array.prototype.every passes its predicate an index, which you can use to get an element’s predecessor:
function isAscending(arr) {
return arr.every(function (x, i) {
return i === 0 || x >= arr[i - 1];
});
}
Here, we’re checking that every item (x) is greater than or equal to the item before it (arr[i - 1]) or has no item before it (i === 0).
Flip >= to <= for isDescending.
"Check if an array is descending, ascending or not sorted using loops"
// define the array
var array = [1,2,3,7];
// keep track of things
var isDescending = true;
var isAscending = true;
// we're looking ahead; loop from the first element to one before the last element
for (var i=0, l=array.length-1; i<l; i++)
{
////////////////////////////////////////////////////////////
// log to the console to show what's happening for each loop iteration
// this is the ith iteration
console.log("loop iteration %s", i);
// breaking isDescending down:
// is this value greater than the next value?
console.log("A: (%s > %s) = %s", array[i], array[i+1], (array[i] > array[i+1]));
// have all values been descending so far?
console.log("B: isDescending: %s", isDescending);
// if this value is greater than the next and all values have been descending so far, isDescending remains true. Otherwise, it's set to false.
console.log("are A and B both true? %s", (isDescending && (array[i] > array[i+1])));
// add a line break for clarity
console.log("");
////////////////////////////////////////////////////////////
// true if this is greater than the next and all other so far have been true
isDescending = isDescending && (array[i] > array[i+1]);
// true if this is less than the next and all others so far have been true
isAscending = isAscending && (array[i] < array[i+1]);
}
if (isAscending)
{
console.log('Ascending');
}
else if (isDescending)
{
console.log('Descending');
}
else
{
console.log('Not Sorted');
}
This is a question that requires some sort of loop, with several if statements because there are several cases you need to tackle:
Array is empty or has only one element.
All items in the array are equal
Array is ascending - delta between 2 elements > 0, but some deltas may be 0
Array is descending - delta between 2 elements < 0, but some deltas may be 0
Not sorted - some deltas are > 0, and some are < 0
Depending on how the sorted is defined in the question, cases 1 & 2 might be regarded as unsorted as well.
function findSortOrder(arr) {
if(arr.length < 2) { // case 1
return 'not enough items'; // can also be 'unsorted'
}
var ascending = null;
var nextArr = arr.slice(1); // create an array that starts from the 2nd element of the original array
for(var i = 0; i < nextArr.length; i++) {
if (nextArr[i] === arr[i]) { // neutral - do nothing
} else if(ascending === null) { // define the the direction by the 1st delta encountered
ascending = nextArr[i] > arr[i];
} else if (ascending !== nextArr[i] > arr[i]) { // case 5
return 'unsorted';
}
}
if(ascending === null) { // case 2
return 'all items are equal'; // can also be 'unsorted'
}
return ascending ? 'ascending' : 'descending'; // cases 3 & 4
}
console.log(findSortOrder([1])); // case 1
console.log(findSortOrder([1, 1, 1, 1])); // case 2
console.log(findSortOrder([1, 1, 2, 3, 7, 7])); // case 3
console.log(findSortOrder([7, 2, 2, 1])); // case 4
console.log(findSortOrder([7, 2, 1, 3, 2, 1])); // case 5
You could use a copy from the second element and check the predecessor for the wanted sort order.
function checkArray(array) {
var aa = array.slice(1);
if (!aa.length) {
return "Just one element";
}
if (aa.every((a, i) => array[i] > a)) {
return "Ascending";
}
if (aa.every((a, i) => array[i] < a)) {
return "Descending";
}
return "Unsorted";
}
console.log(checkArray([1, 2, 3, 4, 5]));
console.log(checkArray([5, 4, 3, 2, 1]));
console.log(checkArray([3, 1, 4, 2, 5]));
console.log(checkArray([42]));
function isAscending(arr = []) {
for (let i = 0; i < arr.length; i++) {
if (arr[i + 1] <= arr[i]) {
return false;
}
}
return true;
}
function isAscending(arr) {
return arr
.slice(1)
.every((num,i) => num >= arr[i]);
}
console.log(isAscending([1,2,3])); // true
console.log(isAscending([12,38,25])); // false
console.log(isAscending([103,398,52,629])); // false
arr.slice(1) --> allows us to start iteration at index 1 instead of 0
we'll iterate over "arr" with "every" & compare the current "num" against the previous "num" with "arr[i]"
function findOrder(array) {
var asc = true;
var desc = true;
if(array.length < 2){
return 'array is too small'
}
for(var i=1, len=array.length;i<len;i++){
//if current element is bigger than previous array is not descending
if(array[i]>array[i-1]){
desc = false;
//if current element is smaller than previous array is not ascending
}else if(array[i]<array[i-1]){
asc = false;
}
if(!asc && !desc){
return 'not sorted'
}
}
if(asc && desc){
return 'array values are equal'
}else if (asc){
return 'array is ascending'
}else {
return 'array is descending'
}
}
Actually we may do even more by creating an Array method like natureOf which can tell us more about the nature of the array than just ascending, descendig or flat. Array.natureOf() shall give us a value between -1 and 1. If it is -1 the array is fully descending and 1 would mean fully ascending of course. Any value inbetween would give us the inclination of the array. As you would guess 0 would mean totally random or flat. (it's fairly easy to insert the logic to distinguish random from flat if that's also needed)
Array.natureOf = function(a){
var nature = a.reduce((n,e,i,a) => i && a[i-1] !== e ? a[i-1] < e ? (n.asc++, n)
: (n.dsc++, n)
: n, {asc:0, dsc:0});
return (nature.asc - nature.dsc) / (a.length-1);
};
var arr = [1,2,3,4,5,6,7,8,9,10,7,11,13,14,15],
brr = Array.from({length:2000000}, _ => ~~(Math.random()*1000000000));
console.log(`The nature of "arr" array is ${Array.natureOf(arr)}`);
console.log(`The nature of "brr" array is ${Array.natureOf(brr)}`);
console.log(checkSort([1, 2, 3, 3, 4, 5]));
console.log(checkSort([5, 4, 3, 2, 1, 1]));
console.log(checkSort([2, 5, 8, 9, 4, 6]));
function checkSort(arr){
var isDescending, isAscending;
isDescending = isAscending = true;
const len = arr.length - 1;
for (var index = 0 ; index < len ; index++){
if(isAscending)
isAscending = arr[index] <= arr[index + 1];// '<=' so as to check for same elements
if(isDescending)
isDescending = arr[index] >= arr[index + 1];//'<=' so as to check for same elements
}
var result = "Array is ";
if (isAscending)
return result.concat("sorted in ascending order");
if (isDescending)
return result.concat("sorted in descending order");
return result.concat("not sorted");
const isAscending=(arr)=>{
for(let i=0;i<arr.length;i++){
if(arr[i+1]<arr[i]){ return false } } return true }

Shifting rows and columns in 2D arrays - Javascript

I have a situation as such:
var array = [
[1,2,3],
[4,5,6],
[7,8,9]
]
And I am trying to create a function that shifts either a row or a column so the result would be:
shiftRow(array, 1)
[
[3,1,2],
[4,5,6],
[7,8,9]
]
shiftColumn(array,1)
[
[7,2,3],
[1,5,6],
[4,8,9]
]
I want the first number to be the last number then continue from there in any instance. I have tried several nested for loops, and I'm quite stuck at figuring this out. Keep in mind I have only been coding for a few months though.
This is what I have so far. It gives me an undefined error at the end and it is moving it the wrong way.
function shiftRow(arr) {
var temp = arr
for(var i = 0; i < temp.length; i++) {
for(var j = 0; j < temp[i].length; j++) {
temp[i][j] = temp[i][j+1]
}
}
return temp;
}
The previous answers looks ok, but lacks one major thing when dealing with array indexes ; validation checks.
You do not want to try to access non-existent array indexes. Therefore, I created a small class to shift your array as needed, with validation. This will throw an Error if either the row or column index is invalid.
class ArrayShifter {
static showArray(array) {
// console.log("Array : ", array);
console.log('------');
for (const [index, elem] of array.entries()) {
console.log(''+elem);
}
}
static validateRowIndex(array, rowIndex) {
if (!isArray(array) || !isInt(rowIndex) || rowIndex <= 0 || rowIndex > array.length) {
throw new Error('The row index is wrong');
}
}
static validateColumnIndex(array, columnIndex) {
if (!isArray(array) || !isInt(columnIndex) || columnIndex <= 0 || columnIndex > array[0].length) {
throw new Error('The column index is wrong');
}
}
static shiftRow(array, rowIndex) {
ArrayShifter.validateRowIndex(array, rowIndex);
array[rowIndex - 1].unshift(array[rowIndex - 1].pop());
return array;
}
static shiftColumn(array, columnIndex) {
ArrayShifter.validateColumnIndex(array, columnIndex);
let prev = array[array.length - 1][columnIndex - 1];
for (const elem of array) {
let tmp = elem[columnIndex - 1];
elem[columnIndex - 1] = prev;
prev = tmp;
}
return array;
}
}
let sourceArray1 = [
[1,2,3],
[4,5,6],
[7,8,9],
];
let sourceArray2 = [
[1,2,3],
[4,5,6],
[7,8,9],
];
let controlArrayShiftRow = [
[3,1,2],
[4,5,6],
[7,8,9],
];
let controlArrayColumnRow = [
[7,2,3],
[1,5,6],
[4,8,9],
];
// arrayShifter.showArray(sourceArray1);
console.log(`Shift row test is ${areArraysEqual(controlArrayShiftRow, ArrayShifter.shiftRow(sourceArray1, 1))}.`);
// arrayShifter.showArray(sourceArray2);
console.log(`Shift column test is ${areArraysEqual(controlArrayColumnRow, ArrayShifter.shiftColumn(sourceArray2, 1))}.`);
//-------------------- Unimportant js functions --------------------
function isArray(arr) {
if (Object.prototype.toString.call([]) === '[object Array]') { //Make sure an array has a class attribute of [object Array]
//Test passed, now check if is an Array
return Array.isArray(arr) || (typeof arr === 'object' && Object.prototype.toString.call(arr) === '[object Array]');
}
else {
throw new Exception('toString message changed for Object Array'); //Make sure the 'toString' output won't change in the futur (cf. http://stackoverflow.com/a/8365215)
}
}
function isInt(n) {
return typeof n === 'number' && parseFloat(n) === parseInt(n, 10) && !isNaN(n);
}
function areArraysEqual(a1, a2) {
return JSON.stringify(a1) == JSON.stringify(a2);
}
The working code can be seen in this codepen.
For row shift you can use Array#unshift and Array#pop methods. And for shifting the column use a Array#forEach method with a temp variable.
var array = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
],
array1 = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
function shiftRow(arr, row) {
arr[row - 1].unshift(arr[row - 1].pop());
return arr;
}
function shiftCol(arr, col) {
var prev = arr[arr.length - 1][col-1];
arr.forEach(function(v) {
var t = v[col - 1];
v[col - 1] = prev;
prev = t;
})
return arr;
}
console.log(shiftRow(array, 1))
console.log(shiftCol(array1, 1))
First, you have to pass two arguments: the array, and the row/column you want to shift. And remember that arrays are zero-based, not 1. So in your example, if you want to shit the first row, you need to pass 0, not 1.
Second, since you want to put the last element at the front, and push others down, you need to loop, for shiftRow, from back to front. Here's a solution. Feel free to improve on it.
function shiftRow(arr, row) {
var temp = arr[row];
var j=temp.length-1;
var x=temp[j];
for(var i = j; i > 0; i--) {
temp[i]=temp[i-1];
}
temp[0]=x;
arr[row]=temp;
}
As you can see it works only on the row you want to shift, and starts from the end, working its way to the front. Before the loop I save the last element (which will be overwritten) and put that in the first slot at the end of the loop.
Given this question :
Transposing a javascript array efficiently
It is sufficient to implement only shiftRow and transpose before and after it if we want to achieve shiftCol
function shiftRow(array,n)
{
let retVal=[[]];
for(i=0;i<array.length;i++)
{
if (i==n)
retVal[i]= array[i].slice(1,array.length).concat(array[i][0]);
else
retVal[i]=array[i];
}
return retVal;
}

Check if Javascript array values are in ascending order

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]
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]));
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;
}
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)
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)
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
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 ;
});
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
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.
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);
}
}
} }

deleting duplicates on sorted array

Just in case you missed, the question is about deleting duplicates on a sorted array. Which can be applied very fast algorithms (compared to unsorted arrays) to remove duplicates.
You can skip this if you already know how deleting duplicates on SORTED arrays work
Example:
var out=[];
for(var i=0,len=arr.length-1;i<len;i++){
if(arr[i]!==arr[i+1]){
out.push(arr[i]);
}
}
out.push(arr[i]);
See?, it is very fast. I will try to explain what just happened.
The sorted arrays *could look like this:
arr=[0,1,1,2,2,3,4,5,5,6,7,7,8,9,9,9];
*the sorting could be ASC or DESC, or by other weird methods, but the important thing is that every duplicated item is next each other.
We stopped at array.length-1 because we don't have anything to check with
Then we added the last element regardless of anything because:
case A:
... ,9,9,9];//we have dup(s) on the left of the last element
case B:
... ,7,9,10];//we don't have dup(s) on the left of the last element
If you really understand what is happening, you will know that we haven't added any 9 on the case A. So because of that, we want to add the last element no matter if we are on case A or B.
Question:
That explained, I want to do the same, but ignoring the undefined value on cases like:
var arr=[];arr[99]=1;//0 through 98 are undefined, but do NOT hold the undefined value
I want to remove those. And on the case I have some real undefined values, these should not be removed.
My poor attempt is this one:
var out=[];
for (var i=0,len=arr.length; i < len - 1;) {
var x = false;
var y = false;
for (var j = i, jo; j < len - 1; j++) {
if (j in arr) {
x = true;
jo = arr[j];
i = j + 1;
break;
}
}
if (x == false) {
break;
}
for (var u = i, yo; u < len - 1; u++) {
if (u in arr) {
y = true;
yo = arr[u];
i = u + 1;
break;
}
}
if (y == false) {
out.push(jo);
break;
}
if (jo !== yo) {
out.push(jo);
}
}
out.push(arr[len - 1]);
I am really lost, any help is appreciated
A modern one-liner using .filter()
arr.filter((e, i, a) => e !== a[i - 1]);
I'm very surprised by the complexity of other answers here, even those that use .filter()
Even using old-school ES5 syntax with no arrow functions:
arr.filter(function (e, i, a) { return e !== a[i - 1] });
Example:
let a = [0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 9];
let b = arr.filter((e, i, a) => e !== a[i - 1]);
console.log(b); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
If you need to mutate the array in place then just use:
arr = arr.filter((e, i, a) => e !== a[i - 1]);
Personally I would recommend against using such complex solutions as the ones in other answers here.
For a start, I'm not entirely certain your original code is kosher. It appears to me that it may not work well when the original list is empty, since you try to push the last element no matter what. It may be better written as:
var out = [];
var len = arr.length - 1;
if (len >= 0) {
for (var i = 0;i < len; i++) {
if (arr[i] !== arr[i+1]) {
out.push (arr[i]);
}
}
out.push (arr[len]);
}
As to your actual question, I'll answer this as an algorithm since I don't know a lot of JavaScript, but it seems to me you can just remember the last transferred number, something like:
# Set up output array.
out = []
# Set up flag indicating first entry, and value of last added entry.
first = true
last = 0
for i = 0 to arr.length-1:
# Totally ignore undefined entries (however you define that).
if arr[i] is defined:
if first:
# For first defined entry in list, add and store it, flag non-first.
out.push (arr[i])
last = arr[i]
first = false
else:
# Otherwise only store if different to last (and save as well).
if arr[i] != last:
out.push (arr[i])
last = arr[i]
This is a one-liner:
uniquify( myArray.filter(function(x){return true}) )
If you don't already have uniquify written (the function you wrote to remove duplicates), you could also use this two-liner:
var newArray = [];
myArray.forEach(function(x) {
if (newArray.length==0 || newArray.slice(-1)[0]!==x)
newArray.push(x)
})
Elaboration:
var a=[];
a[0]=1; a[1]=undefined; a[2]=undefined;
a[10]=2; a[11]=2;
According to OP, array has "five elements" even though a.length==12. Even though a[4]===undefined, it is not an element of the array by his definition, and should not be included.
a.filter(function(x){return true}) will turn the above array into [1, undefined, undefined, 2, 2].
edit: This was originally written with .reduce() rather than .forEach(), but the .forEach() version is much less likely to introduce garbage-collector and pass-by-value issues on inefficient implements of javascript.
For those concerned about compatibility with the 6-year-old MIE8 browser, which does not support the last two editions of the ECMAScript standard (and isn't even fully compliant with the one before that), you can include the code at https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach However if one is that concerned about browser compatibility, one ought to program via a cross-compiler like GWT. If you use jQuery, you can also rewrite the above with only a few extra characters, like $.forEach(array, ...).
Perhaps something like this:
var out = [],
prev;
for(var i = 0; i < arr.length; i++) {
if (!(i in arr))
continue;
if (arr[i] !== prev || out.length === 0) {
out.push(arr[i]);
prev = arr[i];
}
}
The out.length check is to allow for the first defined array element having a value of undefined when prev also starts out initially as undefined.
Note that unlike your original algorithm, if arr is empty this will not push an undefined value into your out array.
Or if you have a new enough browser, you could use the Array.forEach() method, which iterates only over array elements that have been assigned a value.
An explicit way would be to pack the array (remove the undefined) values and use your existing algorithm for the duplicates on that..
function pack(_array){
var temp = [],
undefined;
for (i=0, len = _array.length; i< len; i++){
if (_array[i] !== undefined){
temp.push(_array[i]);
}
}
return temp;
}
I think this is what you want. It's a pretty simple algorithm.
var out = [], previous;
for(var i = 0; i < arr.length; i++) {
var current = arr[i];
if(!(i in arr)) continue;
if(current !== previous) out.push(current);
previous = arr[i];
}
This will run in O(N) time.
A very simple function, the input array must be sorted:
function removeDupes(arr) {
var i = arr.length - 1;
var o;
var undefined = void 0;
while (i > 0) {
o = arr[i];
// Remove elided or missing members, but not those with a
// value of undefined
if (o == arr[--i] || !(i in arr)) {
arr.splice(i, 1);
}
}
return arr;
}
It can probably be more concise, but might become obfuscated. Incidentally, the input array is modified so it doesn't need to return anything but it's probably more convenient if it does.
Here's a forward looping version:
function removeDupes2(arr) {
var noDupes = [],
o;
for (var i=0, j=0, iLen=arr.length; i<iLen; i++) {
o = arr[i];
if (o != noDupes[j] && i in arr) {
noDupes.push(o);
j = noDupes.length - 1;
}
}
return noDupes;
}
PS
Should work on any browser that supports javascript, without any additional libraries or patches.
This solution removes duplicates elements in-place. not recommended for functional programming
const arr =[0,0,1,1,2,2,2,3,4,5,5,6,7,7,8,9,9,9];
const removeDuplicates = (nums) => {
nums.forEach((element, idx) => {
nums.splice(idx, nums.lastIndexOf(element) - idx)
})
}
removeDuplicates(arr)
console.log(arr);
//sort the array
B.sort(function(a,b){ return a - b});
//removing duplicate characters
for(var i=0;i < B.length; i ++){
if(B[i]==B[i + 1])
B.splice(i,1)
}
if element in next index and current position is same remove the element at
current position
splice(targetPosition,noOfElementsToBeRemoved)
I believe what you are trying to achieve is not quite possible, but I could be wrong.
It's like one of those classic CS problems like the one where a barber in a village only shaves the one who don't shave themselves.
If you set the value of an array's index item as undefined, it's not really undefined.
Isn't that the case? A value can only be undefined when it hasn't been initialized.
What you should be checking for is whether a value is null or undefined. If null or duplicate skip the value, else retain it.
If null values and duplicates are what you are trying to skip then below function will do the trick.
function removeDuplicateAndNull(array){
if(array.length==0)
return [];
var processed = [], previous=array[0];
processed.push(array[0]);
for(var i = 1; i < array.length; i++) {
var value = array[i];
if( typeof value !== 'undefined' && value ==null)
continue;
if(value !== previous || typeof value === 'undefined')
processed.push(value);
previous = array[i];
}
return processed;
}
Test cases:
array=[,5,5,6,null,7,7] output =[ ,5,6,7]
array=[ 5,5,,6,null,,7,7] output=[5,,6,,7]
array=[7,7,,] output=[7,]
But even with this function there's a caveat. IF you check third test, the output is [7,]
instead of [7,,] !
If you check the length of the input and output arrays, array.length =3 and output.length=2.
The caveat is not with the function but with JavaScript itself.
This code is written in javascript. Its very simple.
Code:
function remove_duplicates(arr) {
newArr = [];
if (arr.length - 1 >= 0) {
for (i = 0; i < arr.length - 1; i++) {
// if current element is not equal to next
// element then store that current element
if (arr[i] !== arr[i + 1]) {
newArr.push(arr[i]);
}
}
newArr.push(arr[arr.length - 1]);
}
return newArr
}
arr=[0,1,1,2,2,3,4,5,5,6,7,7,8,9,9,9];
console.log(remove_duplicates(arr));
Here is the simple JavaScript solution without using any extra space.
function removeDuplicates(A) {
let i = 0;
let j = i + 1;
while (i < A.length && j < A.length) {
if (A[i] === A[j]) {
A.splice(i, 1);
j=i+1;
} else {
i++;
j++;
}
}
return A;
}
console.log('result', removeDuplicates([0,1,1,2,2,2,2,3,4,5,6,6,7]))
You can try the simple way
function hello(a: [], b: []) {
return [...a, ...b];
}
let arr = removeDuplicates(hello([1, 3, 7], [1, 5, 10]));
arr = removeDuplicates(arr);
function removeDuplicates(array) {
return array.filter((a, b) => array.indexOf(a) === b);
}
let mainarr = arr.sort((a, b) => parseInt(a) - parseInt(b));
console.log(mainarr); //1,3,5,7,10
One liner code
[1,3,7,1,5,10].filter((a, b) => [1,3,7,1,5,10].indexOf(a) === b).sort((a, b) => parseInt(a) - parseInt(b))
Here is simple solution to remove duplicates from sorted array.
Time Complexity O(n)
function removeDuplicate(arr) {
let i=0;
let newArr= [];
while(i < arr.length) {
if(arr[i] < arr[i+1]) {
newArr.push(arr[i])
} else if (i === (arr.length-1)) {
newArr.push(arr[i])
}
i++;
}
return newArr;
}
var arr = [1,2,3,4,4,5,5,5,6,7,7]
console.log(removeDuplicate(arr))
Let's suppose that you have a sorted array and you can't use additional array to find and delete duplicates:
In Python
def findDup(arr, index=1, _index=0):
if index >= len(arr):
return
if arr[index] != arr[_index]:
findDup(arr, index+1, _index+1)
if arr[index] == arr[_index]:
arr = deletedup(arr, index)
findDup(arr, index, _index) #Has to remain same here, because length has changed now
def deletedup(arr, del_index):
del arr[del_index]
return arr
arr = [1, 2, 3, 4, 4, 4, 5, 6, 7, 7, 7, 7, 7]
findDup(arr)
print arr

Categories

Resources