<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://amusiku.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 19 Sep 2026 00:36:59 GMT</lastBuildDate><atom:link href="https://amusiku.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[H2H: For-loop search vs the .indexOf() method]]></title><description><![CDATA[Searching for a specific element in an array is a common task in programming. Two popular methods for searching arrays in JavaScript are iterating over each element using a for loop and Array.prototype.indexOf(). The former is a simple search algorit...]]></description><link>https://amusiku.hashnode.dev/h2h-for-loop-search-vs-the-indexof-method</link><guid isPermaLink="true">https://amusiku.hashnode.dev/h2h-for-loop-search-vs-the-indexof-method</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[indexOf]]></category><category><![CDATA[for loop]]></category><category><![CDATA[arrays]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Austin Musiku]]></dc:creator><pubDate>Wed, 17 May 2023 02:18:05 GMT</pubDate><content:encoded><![CDATA[<p>Searching for a specific element in an array is a common task in programming. Two popular methods for searching arrays in JavaScript are iterating over each element using a for loop and <code>Array.prototype.indexOf()</code>. The former is a simple search algorithm that checks each element in an array sequentially until the target value is found while <code>Array.prototype.indexOf()</code>, still a linear search function, is a built-in JavaScript method that searches for a target value in an array and returns its index if found, or -1 if not found.</p>
<p>In this article, I document my journey of attempting to comprehend the performance discrepancies between the two approaches, the extent of the variation, and above all, the underlying reasons for these differences.</p>
<h2 id="heading-the-tests">The tests</h2>
<p>To test the performance of these two methods, I wrote a simple benchmark script that records the running times of each search method over multiple random-number arrays of varying lengths. The script then calculates the average time taken for each function on each array size.</p>
<p>It's worth noting that these tests specifically measure the worst-case scenario, where the target element is either non-existent or located at the tail end of the array. In situations where the target is at the beginning of the array, both functions perform almost equally and maintain consistent performance across different array sizes. Additionally, when the target is somewhere within the array, the performance of both functions scales proportionally to their respective worst-case times.</p>
<h3 id="heading-lets-break-down-the-code-into-sections">Let's break down the code into sections:</h3>
<p>Setting up the parameters: We first define</p>
<ol>
<li><p><code>ARR_SIZES</code> - the array lengths we want to test,</p>
</li>
<li><p><code>K_TIMES</code> - the number of times we want to run each function,</p>
</li>
<li><p><code>TARGET</code> - target value we are searching for in the array.</p>
</li>
</ol>
<p>I chose a high <code>K_TIMES</code> value to account for the fact that there will be some variance between each test's performance time.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> ARR_SIZES = [<span class="hljs-number">1</span>,<span class="hljs-number">10</span>,<span class="hljs-number">100</span>,<span class="hljs-number">1000</span>,<span class="hljs-number">10</span>_000,<span class="hljs-number">100</span>_000,<span class="hljs-number">1</span>_000_000,<span class="hljs-number">10</span>_000_000,<span class="hljs-number">100</span>_000_000];
<span class="hljs-keyword">let</span> K_TIMES = <span class="hljs-number">10000</span>;
<span class="hljs-keyword">let</span> TARGET = <span class="hljs-number">999</span>_999_999_999;
<span class="hljs-keyword">let</span> results = {};
</code></pre>
<p>Generating the test array: We define a function to generate a new array of random numbers for each test run. The array is of length <code>arrSize</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> generateArray = <span class="hljs-function">(<span class="hljs-params">arrSize</span>) =&gt;</span> {
    <span class="hljs-comment">// reset the array for each test</span>
    <span class="hljs-keyword">let</span> array = [];
    <span class="hljs-comment">// populate the array with random nums</span>
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i&lt;arrSize; i++) {
        array.push(<span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random()*<span class="hljs-number">1</span>_000_000))
    }
    <span class="hljs-keyword">return</span> array;
}
</code></pre>
<p>The search methods: We define the two search methods we want to test: for-loop search and <code>Array.prototype.indexOf()</code>.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> loopFind = <span class="hljs-function">(<span class="hljs-params">array, target</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> length = array.length;
    <span class="hljs-comment">// loop through the array until the value is found</span>
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i&lt;length; i++) {
        <span class="hljs-keyword">if</span>(array[i] === target){ 
            <span class="hljs-keyword">return</span> i
        }
    }
    <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
}

<span class="hljs-keyword">let</span> indexOfFind = <span class="hljs-function">(<span class="hljs-params">array, target</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> array.indexOf(target)
}
</code></pre>
<p>Running the tests: We define a function <code>testRun</code> to run each search function <code>K_TIMES</code> times on the test array, record the time taken for each run and calculate the average time taken for each function for that specific array size.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> testRun = <span class="hljs-function">(<span class="hljs-params">testName, testFunction, arraySize</span>) =&gt;</span> {
    <span class="hljs-comment">// generate a new array for each test</span>
    <span class="hljs-keyword">let</span> array = generateArray(arraySize);

    <span class="hljs-comment">// run the test K_TIMES times and record the </span>
    <span class="hljs-comment">// time taken for each run in the results object</span>
    <span class="hljs-keyword">let</span> i = K_TIMES
    <span class="hljs-keyword">while</span> (i--) {

        <span class="hljs-comment">// The fun part</span>
        <span class="hljs-comment">// performance.now() returns a high-precision timestamp down to 1/1000th of a millisecond</span>
        <span class="hljs-keyword">let</span> startTime = performance.now();
        testFunction(array, TARGET);
        <span class="hljs-keyword">let</span> endTime = performance.now();

        <span class="hljs-comment">// create a new array if the test name is not in the results</span>
        <span class="hljs-keyword">if</span>(!results[testName]) {
            results[testName] = [];
        }
        <span class="hljs-comment">// push the time taken (milliseconds) to the results</span>
        results[testName].push(endTime-startTime);
    }

    <span class="hljs-comment">// calculate the average time taken for the test</span>
    <span class="hljs-keyword">let</span> avg = results[testName].reduce(<span class="hljs-function">(<span class="hljs-params">a,b</span>) =&gt;</span> a+b)/K_TIMES;

    <span class="hljs-keyword">if</span>(!results[<span class="hljs-string">'avgs'</span>]) { 
        results[<span class="hljs-string">'avgs'</span>] = {}
    }
    results[<span class="hljs-string">'avgs'</span>][testName] = <span class="hljs-built_in">Number</span>(avg.toFixed(<span class="hljs-number">4</span>));
}
</code></pre>
<p>Loop over all the array sizes and call the test runner with the function to be tested alongside all the necessary values it will need.</p>
<pre><code class="lang-javascript">ARR_SIZES.forEach(<span class="hljs-function">(<span class="hljs-params">arrSize</span>) =&gt;</span> {
    testRun(<span class="hljs-string">'loopFind'</span>, loopFind, arrSize);
    testRun(<span class="hljs-string">'indexOf'</span>, indexOfFind, arrSize);
});
</code></pre>
<h2 id="heading-test-results">Test results</h2>
<p>Here are the test results:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Array size</td><td>Loopfind</td><td>indexOf</td></tr>
</thead>
<tbody>
<tr>
<td>1</td><td>0.0003</td><td>0.0001</td></tr>
<tr>
<td>10</td><td>0.0005</td><td>0.0002</td></tr>
<tr>
<td>100</td><td>0.0007</td><td>0.0005</td></tr>
<tr>
<td>1,000</td><td>0.0014</td><td>0.0018</td></tr>
<tr>
<td>10,000</td><td>0.0078</td><td>0.0135</td></tr>
<tr>
<td>100,000</td><td>0.0722</td><td>0.2632</td></tr>
<tr>
<td>1,000,000</td><td>1.0825</td><td>2.2119</td></tr>
<tr>
<td>10,000,000</td><td>12.3631</td><td>21.8442</td></tr>
<tr>
<td>100,000,000</td><td>126.0553</td><td>216.772</td></tr>
</tbody>
</table>
</div><p>Looking at the results, we can see that for small arrays with up to 100 elements, both <code>loopFind()</code> and <code>indexOfFind()</code> have similar performance, with both methods taking less than 1 microsecond to complete the search.</p>
<p>However, for larger arrays, <code>loopFind()</code> starts to perform better than <code>indexOfFind()</code>. For example, past 10,000 elements, <code>loopFind()</code> performs up to twice as fast as <code>indexOfFind()</code>. This indicates that as the size of the array increases, <code>loopFind()</code> becomes more efficient than <code>indexOfFind()</code>.</p>
<h3 id="heading-why">Why?</h3>
<p>There could be a ton of reasons why there is a significant contrast between the two on various occasions. One of them is how <code>Array.prototype.indexOf()</code> is implemented in various javascript engines.</p>
<p>The guidelines for how various functions are implemented are outlined by Ecma International in a specification known as ECMAScript. If you're interested in the details of the <code>Array.prototype.indexOf()</code> spec, check out <a target="_blank" href="https://tc39.es/ecma262/#sec-array.prototype.indexof">Array.Prototype.indexof()</a>. The function has multiple steps which I'll roughly summarise as follows:</p>
<ol>
<li><p>Casting the array to an object. This is common in many methods of <code>Array.prototype</code>, including <code>Array.prototype.indexOf()</code>. This ensures that the functions can handle array-like objects, which are simply objects with indexed properties and a length property e.g., HTMLCollections, NodeLists, strings, the arguments object etc.</p>
</li>
<li><p>Initializing all the necessary state variables. These variables include the current index of the search, the target value, and a Boolean flag to indicate whether the target value has been found.</p>
</li>
<li><p>Looping through the object's keys while testing whether the key's value is equal to the target is the core of the function. The loop iterates through the object's keys, and for each key, the function checks whether the key's value is equal to the target value. If the key's value is equal to the target value, the function returns the key. If the key's value is not equal to the target value, the function continues looping.</p>
</li>
</ol>
<p>Although the extra steps are necessary to handle different types of objects consistently, they add overhead to what may seem like a simple search algorithm and have a compounding effect on the performance of the function.</p>
<p>Moreover, the implementation of JavaScript's built-in functions and objects varies across JavaScript engines or runtimes, with each engine employing different optimization techniques. This can result in potential slight differences in overall performance across different environments.</p>
<p>If you're interested in where the devil is at, here are links to where you can find the source code of some popular JavaScript engines:</p>
<ul>
<li><p>V8: <a target="_blank" href="https://github.com/v8/v8">https://<strong>github.com/v8/v8</strong></a><strong>.</strong></p>
</li>
<li><p>SpiderMonkey: <a target="_blank" href="https://searchfox.org/mozilla-central/source/js">https://searchfox.org/mozilla-central/source/js</a>.</p>
</li>
<li><p>JavaScriptCore: <a target="_blank" href="https://github.com/WebKit/WebKit/tree/main/Source/JavaScriptCore">https://github.com/WebKit/WebKit/tree/main/Source/JavaScriptCore</a></p>
</li>
</ul>
<h2 id="heading-verdict">Verdict</h2>
<p>When considering the choice between iterating over each element using a for loop and the built-in <code>indexOf</code> method for your solution, here are some considerations:</p>
<p><strong>Code Simplicity</strong></p>
<p><code>indexOf</code> is a built-in method in JavaScript, so it follows established conventions and is widely understood by developers. Using <code>indexOf</code> can make your code more readable and easier to understand by other programmers. If the performance difference is not critical or the code readability is more important, I recommend using the built-in <code>indexOf</code>.</p>
<p><strong>Array Length</strong></p>
<p>For small arrays, the performance difference between the two is negligible. Both methods can be used interchangeably without significant impact. However, as the array size grows larger, iterating over each element tends to outperform <code>indexOf</code> in the worst-case scenario.</p>
<h2 id="heading-final">Final</h2>
<p>It's important to note that the choice between the two can be subjective and depends on the specific context and requirements of your problem. It's always good to perform benchmark tests in your target environment to evaluate the actual performance and make an informed decision.</p>
]]></content:encoded></item></channel></rss>