<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: LJ Seng</title>
    <description>The latest articles on DEV Community by LJ Seng (@leejunseng).</description>
    <link>https://dev.to/leejunseng</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F222261%2F709d9de5-dcdf-46a6-a2e0-4b656c6824ea.jpg</url>
      <title>DEV Community: LJ Seng</title>
      <link>https://dev.to/leejunseng</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leejunseng"/>
    <language>en</language>
    <item>
      <title>Array Intersection Algorithms Compared</title>
      <dc:creator>LJ Seng</dc:creator>
      <pubDate>Fri, 23 Jun 2023 06:37:33 +0000</pubDate>
      <link>https://dev.to/leejunseng/array-intersection-algorithms-compared-9kk</link>
      <guid>https://dev.to/leejunseng/array-intersection-algorithms-compared-9kk</guid>
      <description>&lt;p&gt;Finding the intersection between two arrays is a common task in programming, and there are multiple ways to approach this problem. In this article, we will compare two algorithms implemented in JavaScript that find the intersection between two arrays. We will evaluate their space and time complexity to understand their efficiency and performance.&lt;/p&gt;

&lt;p&gt;Algorithm 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;intercept&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;arr2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Algorithm 2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arr2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;computeIntercept&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;array2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;array2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;theSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;intercept&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;computeIntercept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arr1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Space Complexity
&lt;/h2&gt;

&lt;p&gt;The space complexity of an algorithm refers to the amount of memory required by the algorithm to solve a problem. In both algorithms, we are using additional data structures to store intermediate results.&lt;/p&gt;

&lt;p&gt;Algorithm 1 uses the filter function to create a new array containing the intersecting elements. This algorithm does not require any additional space apart from the resulting array, which will have a maximum size equal to the smaller of the two input arrays. Therefore, the space complexity of Algorithm 1 is O(min(n, m)), where n and m are the sizes of the input arrays.&lt;/p&gt;

&lt;p&gt;Algorithm 2 creates a Set from the first array, which requires additional space to store the unique elements. The space complexity of creating a Set is O(n), where n is the size of the first array. The resulting array obtained from filtering the second array will also have a maximum size equal to the smaller of the two input arrays. Hence, the overall space complexity of Algorithm 2 is O(n + min(n, m)).&lt;/p&gt;

&lt;h2&gt;
  
  
  Time Complexity
&lt;/h2&gt;

&lt;p&gt;The time complexity of an algorithm refers to the amount of time taken by the algorithm to solve a problem. It measures the number of operations performed as the input size increases.&lt;/p&gt;

&lt;p&gt;Algorithm 1 utilizes the includes function inside the filter function. The includes function has a time complexity of O(m), where m is the size of the second array. The filter function iterates over the elements of the first array, resulting in a time complexity of O(n). Therefore, the overall time complexity of Algorithm 1 is O(n * m).&lt;/p&gt;

&lt;p&gt;Algorithm 2 creates a Set from the first array, which takes O(n) time, where n is the size of the first array. Filtering the second array has a time complexity of O(m), where m is the size of the second array. Thus, the time complexity of Algorithm 2 is O(n + m).&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison
&lt;/h2&gt;

&lt;p&gt;Comparing the space and time complexities of the two algorithms, we can make the following observations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Algorithm 1 has a better space complexity than Algorithm 2. &lt;/li&gt;
&lt;li&gt;Algorithm 2 has a better time complexity than Algorithm 1. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Algorithm 1 is more space-efficient, but Algorithm 2 is more time-efficient when finding the intersection between two arrays. The choice between the algorithms depends on the specific requirements of the application, such as the available memory and the size of the input arrays.&lt;/p&gt;

&lt;p&gt;If you have an alternative algorithm or a more efficient solution, please feel free to share it. 🙂&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>spacetimecomplexity</category>
      <category>algorithms</category>
      <category>interview</category>
    </item>
    <item>
      <title>The elegance of bash chaining operators</title>
      <dc:creator>LJ Seng</dc:creator>
      <pubDate>Sun, 22 Mar 2020 08:41:53 +0000</pubDate>
      <link>https://dev.to/leejunseng/the-elegance-of-bash-chaining-operators-56m1</link>
      <guid>https://dev.to/leejunseng/the-elegance-of-bash-chaining-operators-56m1</guid>
      <description>&lt;p&gt;I am new to bash scripting. &lt;/p&gt;

&lt;p&gt;In my quest to pick it up, I begin to heartily appreciate chaining operators. With the help of chaining operators, I may not need &lt;code&gt;if&lt;/code&gt; conditional check in bash as often as other programming languages, i.e. Java or PHP. &lt;/p&gt;

&lt;p&gt;Furthermore, to my surprise, lesser &lt;code&gt;if&lt;/code&gt; does not degrade the expressiveness of the script. Instead, it is more elegant and concise once I understand the quirk of it. &lt;/p&gt;

&lt;p&gt;Let's see what do I mean by looking at the following example.&lt;/p&gt;

&lt;p&gt;I need to write a bash script that make sure at any instance of time there is only a maximum of 10 certain files in a directory. &lt;/p&gt;

&lt;p&gt;My first version of the script goes like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;

&lt;span class="c"&gt;##### Variable declaration #####&lt;/span&gt;

&lt;span class="nv"&gt;MY_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/rotateLog
&lt;span class="nv"&gt;MAX_FILE_COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10

&lt;span class="c"&gt;##### Method definition #####&lt;/span&gt;

_delete_oldest_file&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-1tr&lt;/span&gt; &lt;span class="nv"&gt;$MY_DIR&lt;/span&gt;/temp.log.&lt;span class="k"&gt;*&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; | xargs &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;##### Main #####&lt;/span&gt;

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;FILE_COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-1tr&lt;/span&gt; &lt;span class="nv"&gt;$MY_DIR&lt;/span&gt;/temp.log.&lt;span class="k"&gt;*&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$FILE_COUNT&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; &lt;span class="nv"&gt;$MAX_FILE_COUNT&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;_delete_oldest_file
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Program flow is pretty straight forward, described below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check current file count in the directory&lt;/li&gt;
&lt;li&gt;Remove the oldest file from directory if there is more than what is needed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;if&lt;/code&gt; conditional check is always the de facto approach to tackle any sort of decision making problem. This script is okay.&lt;/p&gt;

&lt;p&gt;Then, as I learn about chaining operators, i.e. &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;, &lt;code&gt;;&lt;/code&gt;, etc, which are used to chain commands together, I think the script could be rewritten in a more concise manner. Let's focus on &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; for the moment being. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; is used to chain commands together, such that the next commands is run &lt;strong&gt;if and only if&lt;/strong&gt; the preceding command exited without error (exit code of &lt;code&gt;0&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Coupled with the fact that bash numeric comparison operators observe following behavior:&lt;/p&gt;

&lt;p&gt;If numeric comparison is satisfied, exit code shall be &lt;code&gt;0&lt;/code&gt;. Else, exit code shall be &lt;code&gt;1&lt;/code&gt;. To illustrate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; 1 &lt;span class="nt"&gt;-gt&lt;/span&gt; 10 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="go"&gt;1
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; 11 &lt;span class="nt"&gt;-gt&lt;/span&gt; 10 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="go"&gt;0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Therefore, the original script could be revised to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;FILE_COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-1tr&lt;/span&gt; &lt;span class="nv"&gt;$MY_DIR&lt;/span&gt;/temp.log.&lt;span class="k"&gt;*&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;

    &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$FILE_COUNT&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; &lt;span class="nv"&gt;$MAX_FILE_COUNT&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; _delete_oldest_file
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is especially helpful if I have a flow involving many steps. Let's consider I have a 3 steps flow such that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;_do_A()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;_do_B()&lt;/code&gt; if &lt;code&gt;_do_A()&lt;/code&gt; is successfully executed&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;_do_C()&lt;/code&gt; if &lt;code&gt;_do_B()&lt;/code&gt; failed to execute&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without the help of chaining operators, I likely need 3 &lt;code&gt;if&lt;/code&gt; checking to deliver the flow. But with the help of chaining operators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;_do_A&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; _do_B&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; _do_C&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Elegant. Isn't it? 😎 &lt;/p&gt;

&lt;p&gt;Now, let's imagine we have a 10 steps flow. Isn't that chaining operators a life savior?&lt;/p&gt;

</description>
      <category>bash</category>
    </item>
  </channel>
</rss>
