Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I avoid looping through multiple arrays

Tags:

javascript

I'm trying to pass a class based on the url. Currently, the 2 for-loops are excecuted at all times. Is there a way to write it cleaner to avoid executing any unnecessary code?

const arrCommon = ['foo1', 'foo2', 'foo3', 'foo4'];
const arrOther = ['bar1', 'bar2', 'bar3'];

const activeUrl = window.location.href;
const activePage = activeUrl.substring(activeUrl.lastIndexOf('/') + 1);

for(let i=0; i<arrCommon.length; i++) {
    if (activePage == arrCommon[i])
         //if 'foo1, foo2 foo3 or foo4' add class to element 1
}

for(let i=0; i<arrOther.length; i++) {
    if (activePage == arrOther[i]) {
         //if 'bar1' add class to element 2
         //if 'bar2' add class to element 3
         //...
    }
}
like image 654
Fergoso Avatar asked Jan 13 '21 01:01

Fergoso


People also ask

What is array looping?

The Basic For Loop JavaScript for loops iterate over each item in an array. JavaScript arrays are zero based, which means the first item is referenced with an index of 0. Referencing items in arrays is done with a numeric index, starting at zero and ending with the array length minus 1.

How do I iterate over two arrays in JavaScript?

To use forEach to loop through two arrays at the same time in JavaScript, we can use the index parameter of the forEach callback to get the element with the same index from the 2nd array. const n = [1, 2, 3, 5, 7, 8, 9, 11, 12, 13]; const m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; n.

Why do you use a for loop when using arrays?

Why do we use for loops with arrays? Since for loops have the counting variable built in, they help us to quickly access all elements in an array. What are arrays used for in programming? Storing large amounts of the same type of data.

Can we use loop in array?

You can loop through the array elements with the for loop, and use the length property to specify how many times the loop should run.


3 Answers

To avoid O(n) iterations, use a Set or Map instead, which should have "sublinear" lookup time - typically O(1).

const setCommon = new Set(['foo1', 'foo2', 'foo3', 'foo4']);
const mapOther = new Map(['bar1', el2], ['bar2', el3], ['bar3', el4]]);

const activeUrl = window.location.href;
const activePage = activeUrl.substring(activeUrl.lastIndexOf('/') + 1);

if (setCommon.has(activePage)) {
    ...
}

if (mapOther.has(activePage)) {
    let el = mapOther.get(activePage);
    ...
}
like image 67
Alnitak Avatar answered Oct 04 '22 13:10

Alnitak


Yes, however, this is really not necessary. O(n) operations, as you depict, aren't desirable targets for refactoring and constitute micro-optimizations. As such, this will more than likely harm readability at the insignificant gain of skipping a few instructions.

Here is how you would do it:

const arrCommon = ['foo1', 'foo2', 'foo3', 'foo4'];
const arrOther = ['bar1', 'bar2', 'bar3'];

const activeUrl = window.location.href;
const activePage = activeUrl.substring(activeUrl.lastIndexOf('/') + 1);

for(let i = 0, m = Math.max(arrCommon.length,arrOther.length); i < m; i++){
 if(activePage == arrCommon[i]){
  //if 'foo1, foo2 foo3 or foo4' add class to element 1

  // search complete
  break;
 }
 if(activePage == arrOther[i]){
   //if 'bar1' add class to element 2
   //if 'bar2' add class to element 3
   //...

  // search complete
  break;
 }
}

Addendum

It was raised in the comments that this approach results in more instructions executed. Indeed, because of the conditional short circuit this did execute more instructions in the given scenario, although only barely. In the example given by the OP it executes one extra instruction..... But still, the main point was to end up at O(n), which this is, and combine the multiple loops into one loop. Using a break here will still be O(n) but the combined loop will end up less instructions on average. In addition, the undefined check can be removed to reduce instructions. This is now faster for essentially every scenario in this design; if we were to be examining the situation where exceptionally large sets of lookups were in place, a different approach would be more applicable, but this is rather contained.

There is also the opportunity to use an O(1) lookup as shown in other answers, which still require O(n) setup so long as arrays are involved (creating the comparisons as an object would allow O(1) lookup and not require a mapping from the arrays). Without changing the definition of the items, that is not necessarily optimizing this any more than O(n), but is at least decent to read when composed properly.

Overall, this type of discussion is the exact reason why micro optimizing your code is a bad idea. It wastes time and effort at the most minimal of gain.

Refactoring

Refactoring into a form which would allow O(1) execution from the original design would result in the most performance, albeit not needed in this case as noted above with micro optimizations. This is solely as an aside.

const activePage = 'foo3';

const commonStyles = {};
commonStyles.foo1 = commonStyles.foo2 = commonStyles.foo3 = commonStyles.foo4 = function(){
 // add class to element 1
 console.log('common');
};

const otherStyles = {};
otherStyles.bar1 = otherStyles.bar2 = otherStyles.bar3 = function(){
 //if 'bar1' add class to element 2
 //if 'bar2' add class to element 3
 //...
 console.log('other');
};

(commonStyles[activePage]&&commonStyles[activePage](),otherStyles[activePage]&&otherStyles[activePage]());
like image 33
Travis J Avatar answered Oct 04 '22 13:10

Travis J


Unless I'm missing something, you could use a Javascript object as a dictionary (or a Map), in order to get the element id directly:

const idByPage = {
  foo1: 1, foo2: 1, foo3: 1, foo4: 1,
  bar1: 2,
  bar2: 3,
  bar3: 4
}

var page = 'bar2';

if (idByPage.hasOwnProperty(page)) {
  console.log('element' + idByPage[page]);
  // Add class to ('element' + idByPage[page])
  // ...
}
like image 39
Eric Duminil Avatar answered Oct 04 '22 13:10

Eric Duminil