{"id":5941,"date":"2025-02-19T03:05:11","date_gmt":"2025-02-19T11:05:11","guid":{"rendered":"https:\/\/wonghoi.humgar.com\/blog\/?p=5941"},"modified":"2025-04-30T11:47:54","modified_gmt":"2025-04-30T19:47:54","slug":"dictionary-of-equivalent-analogous-concepts-in-programming-languages","status":"publish","type":"post","link":"https:\/\/wonghoi.humgar.com\/blog\/2025\/02\/19\/dictionary-of-equivalent-analogous-concepts-in-programming-languages\/","title":{"rendered":"Dictionary of equivalent\/analogous concepts in programming languages"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><\/td><td>Common<\/td><td>C<\/td><td>C++<\/td><td>MATLAB<\/td><td>Python<\/td><\/tr><tr><td><\/td><td>Variable arguments<\/td><td><code>&lt;stdarg.h&gt;<\/code><br><code>T f(...)<\/code> <br>Packed in <code>va_arg<\/code><\/td><td>Very BAD! <br><br>Cannot overload<br>when signatures are uncertain.<\/td><td><code>varargin<\/code><br><code>varargout<\/code><br><br>Both packed as cells. <br><br>MATLAB does not have <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/49071-kwargify\">named arguments<\/a><\/td><td><code>*args<\/code> (simple, stored as tuples)<br><br><code>**kwargs<\/code> (specify input by keyword, stored as a dictionary)<\/td><\/tr><tr><td><\/td><td>Referencing<\/td><td><br>N\/A<\/td><td><code>operator[]<\/code><\/td><td><code>(_)<\/code> is for references<br><code>subsindex<br>subsassgn<\/code><br><br><code>[_]<\/code> is for concat <br><code>{_}<\/code> is for (un)pack<\/td><td><code>__getitem__()<br>__setitem__()<\/code><\/td><\/tr><tr><td><\/td><td>Default<br>values<\/td><td>N\/A<\/td><td>Supported<\/td><td>Not supported.<br>Manage with <code>inputParser()<\/code> or <br>newer <code>arguments<\/code><\/td><td>Non-intuitive static data behavior. Stick to <code>None<\/code> or immutables.<\/td><\/tr><tr><td><\/td><td>Name-Value<br>Argument<br>Matching<\/td><td><\/td><td><\/td><td>Old way:<br><code>.., 'PropName', Value<\/code><br>and parse <code>varargin<\/code><br><br>Since R2021a:<br><code>Name=Value<\/code><br><code>options<\/code> in <code>arguments<\/code><\/td><td><code>Name=Value<\/code><br><code>**kwargs<\/code><\/td><\/tr><tr><td><\/td><td>Major<br>Dimension<\/td><td>Row<\/td><td>Row<\/td><td>Column<\/td><td>Row (Native\/Numpy)<br>Column for Pandas<\/td><\/tr><tr><td><\/td><td>Constness<\/td><td><code>const<\/code><\/td><td><code>const<\/code><\/td><td>Only in classes<\/td><td>N\/A (Consenting adults)<\/td><\/tr><tr><td><\/td><td>Variable<br>Aliasing<\/td><td>Pointers<\/td><td>References<\/td><td>NO! Rely on Copy-on-write<br>(No in-place functions*)<br><br>Handle classes under limited circumstances<\/td><td>References<\/td><\/tr><tr><td><\/td><td><code>=<\/code> assignment<\/td><td>Copy one<br>element<\/td><td>Values: Copy<br>References: Bind<\/td><td>New Copy<br>Copy-on-write<\/td><td>NO VALUES<br>Bind references only<br>(could be to unnamed objects)<\/td><\/tr><tr><td><\/td><td>Chained<br>access operators<\/td><td>N\/A<\/td><td>Difficult to operator overload it right<\/td><td>Difficult to get it right. MATLAB had some chaining bugs with <code>dataset()<\/code> as well.<\/td><td>Chains correctly natively<\/td><\/tr><tr><td><\/td><td>Assignment<br>expressions<br>(assignment evaluates to assigned lvalue)<\/td><td><code>=<\/code><\/td><td><code>=<\/code><\/td><td>N\/A<\/td><td><a href=\"https:\/\/peps.python.org\/pep-0572\/\">Named Expression<\/a> <code>:=<\/code> <\/td><\/tr><tr><td><\/td><td>Version Management<\/td><td><\/td><td><\/td><td><code>verLessThan()<\/code><br><a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/ismatlabreleaseolderthan.html\"><code>isMATLABReleaseOlderThan<\/code><\/a><\/td><td><code>virtenv<\/code> (Virtual Environment)<\/td><\/tr><tr><td><\/td><td>Exponentiation<\/td><td><code>&lt;math.h&gt;<\/code><br><code>pow()<\/code><\/td><td><code>&lt;cmath&gt;<\/code><br><code>pow()<\/code><\/td><td><code>^<\/code><\/td><td><code>**<\/code><\/td><\/tr><tr><td><\/td><td>Stream<br>(Conveyor belt mechanism. Saves memory)<\/td><td>I\/O (std, file, sockets)<br><\/td><td><code>iterator<\/code> in<br>STL containers<\/td><td>MATLAB doesn&#8217;t do references. Just increment indices.<\/td><td>iterators (uni-directional only)<br><code>iter(): __iter__()<\/code><br><code>next(): __next__()<\/code><\/td><\/tr><tr><td><\/td><td>Looping<\/td><td>for(init, cont_cond, next)<\/td><td>C-style<br><br>for(auto running: iterable)<\/td><td>for k = array to iterate<br><\/td><td>list-comp<br><br>for (index, thing) in enumerate(lists)<\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><td><\/td><td><\/td><td><\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Since MATLAB doesn&#8217;t do references, iterators (by extension generators) and functions that do in-place operations do not make sense (unless you bend it very hard with anti-patterns such as handles and dbstack).<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Data Types<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>Common<\/td><td>C<\/td><td>C++<\/td><td>MATLAB<\/td><td>Python<\/td><\/tr><tr><td>Sets<\/td><td>N\/A<\/td><td><code>std::set<\/code><\/td><td>Only set operations, not set data type<\/td><td><code>{ , , ...}<\/code><\/td><\/tr><tr><td>Dictionaries<\/td><td><\/td><td><code>std::unordered_map<\/code><\/td><td>&#8211; Dynamic fieldnames<br>(qualified varnames as keys)<br>&#8211; <code>containers.Map()<\/code> or <code><a href=\"https:\/\/www.mathworks.com\/help\/matlab\/dictionary.html\">dictionary<\/a>()<\/code> since R2022b<\/td><td>Dictionaries<br><code>{key:value}<\/code><br>(Native)<\/td><\/tr><tr><td>Heterogeneous containers<\/td><td><\/td><td><\/td><td>cells <code>{}<\/code><\/td><td>lists (mutable)<br>tuples (immutable)<\/td><\/tr><tr><td>Structured<br>Heterogeneous containers<\/td><td><\/td><td><\/td><td><code>table()<\/code><br><code>dataset()<\/code> [Old]<br><br>Mix in classes<\/td><td>Pandas Dataframe<\/td><\/tr><tr><td>Array, <br>Matrices &amp;<br>Tensors<\/td><td><\/td><td><\/td><td>Native <code>[ , ; , ]<\/code><\/td><td>Numpy\/PyTorch<\/td><\/tr><tr><td>Records<\/td><td>struct<\/td><td>class<br>(members)<\/td><td>dynamic field (structs)<br>properties (class)<br><br><code>getfield()\/setfield()<\/code><\/td><td>No structs<br>(use dicts)<br><br>attribute (class)<br><code>getattr()\/setattr()<\/code><\/td><\/tr><tr><td>Type deduction<\/td><td>N\/A<\/td><td><code>auto<\/code><\/td><td>Native<\/td><td>Native<\/td><\/tr><tr><td>Type extraction<\/td><td>N\/A<\/td><td><code>decltype()<\/code> for compile time (static)<br><br><code>typeid()<\/code> for RTTI (runtime)<\/td><td><code>class()<\/code><\/td><td><code>type()<\/code><\/td><\/tr><tr><td>Categorical Arrays<\/td><td><\/td><td><code>categorical()<\/code><br>Previously<br><code>ordinal()\/nominal()<\/code> <\/td><td><code>pd.cut(x, bins, labels)<\/code><\/td><td><\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Native sets operations in Python are not stable and there&#8217;s no option to use stable algorithm like MATLAB does. Consider installing <code>orderly-set<\/code> package.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Array Operations<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><\/td><td>Common<\/td><td>MATLAB<\/td><td>Python<\/td><\/tr><tr><td><\/td><td>Repeat<\/td><td><code>repmat()<\/code><\/td><td><code>[] * N<\/code><br><code>np.repeat()<\/code><\/td><\/tr><tr><td><\/td><td>Logical Indexing<\/td><td>Native<\/td><td>List comprehension<br>Boolean Indexing (Numpy)<\/td><\/tr><tr><td><\/td><td>Equally spaced numbers<\/td><td>Internally <code>colon()<\/code>:<br><code>start:step:end<\/code><br><br><code>linspace<\/code>\/<code>logspace<\/code><\/td><td><code>range(begin, past_end, step)<\/code><br>produces an iterator<br><br><code>list(range())<\/code> or <code>tuple(range())<\/code> <br>iterates to realize the vector<\/td><\/tr><tr><td><\/td><td>Equally spaced indexing<\/td><td>MATLAB has no generators, <br>so produced vector only<\/td><td><code>[start:past_end:step]<\/code> is internally<br><code>slice()<\/code> which produces a <em><strong>slice<\/strong><\/em> object, not range\/lists\/tuple. Faster but <strong>not iterable<\/strong><\/td><\/tr><tr><td><\/td><td>Shallow copy<\/td><td>Deep copy-on-write<\/td><td>Slice: <code>x = y[:]<\/code><br><code>copy.copy()<\/code><\/td><\/tr><tr><td><\/td><td>Deep copy<\/td><td>Deep copy-on-write<\/td><td><code>copy.deepcopy()<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Editor Syntax<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><\/td><td>Common<\/td><td><\/td><td>C<\/td><td>C++<\/td><td>MATLAB<\/td><td>Python<\/td><\/tr><tr><td><\/td><td>Commenting<\/td><td><\/td><td><code>\/* ... *\/<\/code><br><br><code>\/\/<\/code> (only for newer C)<\/td><td><code>\/\/<\/code> (single line)<br><br><code>\/* ... *\/<\/code> (block)<\/td><td><code>%<\/code> (single line)<br><br>(Block):<br><code>%{ <br>... <br>%}<\/code> <\/td><td><code>#<\/code> (single line)<br><br><code>\"\"\"<\/code> or <code>'''<\/code><br>is docstring which might be undersirably picked up<\/td><\/tr><tr><td><\/td><td>Reliable multi-line<br>commenting<br>(IDE)<\/td><td><\/td><td><\/td><td><\/td><td>Ctrl+(Shift)+<code>R<\/code>(Windows), <code>\/<\/code> (Mac or Linux)<\/td><td>[Spyder]:<br>Ctrl+<code>1<\/code>(toggle), <code>4<\/code>(comment), <code>5<\/code>(uncomment)<\/td><\/tr><tr><td><\/td><td>Code cell<br>(IDE)<\/td><td><\/td><td><\/td><td><\/td><td><code>%%<\/code><\/td><td>[Spyder]: <br><code># %%<\/code><\/td><\/tr><tr><td><\/td><td>Line<br>Continuation<\/td><td><\/td><td><code>\\<\/code><\/td><td><code>\\<\/code><\/td><td><code>...<\/code><\/td><td><code>\\<\/code><\/td><\/tr><tr><td><\/td><td>Console<br>Precision<\/td><td><\/td><td><\/td><td><\/td><td><code>format<\/code><\/td><td><code><a href=\"https:\/\/ipython.readthedocs.io\/en\/stable\/interactive\/magics.html#magic-precision\">%precision<\/a><\/code> (IPython)<\/td><\/tr><tr><td><\/td><td>Clear variables<\/td><td><\/td><td><\/td><td><\/td><td><code>clear<\/code> \/ <code>clearvars<\/code><\/td><td><code>%reset -sf<\/code> (IPython)<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Macros only make sense in C\/C++. This makes code less transparent and is frowned upon in higher level programming languages. Even its use in C++ should be limited. Use inline functions whenever possible.<br><br>Python is messy about the workspace, so if you just delete <\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Object Oriented Programming Constructs<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><\/td><td>Common<\/td><td><\/td><td>C++<\/td><td>MATLAB<\/td><td>Python<\/td><\/tr><tr><td><\/td><td>Getters<br>Setters<\/td><td><\/td><td>No native syntax. <br><br>Name mangle (prefix or suffix) yourself to manage<\/td><td>Define methods:<br><code>get.<em>x<\/em><\/code><br><code>set.<em>x<\/em><\/code><\/td><td>Getter:<br><code>@property<br>def x(self): ...<\/code><br><br>Setter:<br><code>@x.setter<br>def x(self, value): ...<\/code><\/td><\/tr><tr><td><\/td><td>Deleters<\/td><td><\/td><td>Members can&#8217;t be<br>changed on the fly<\/td><td>Members can&#8217;t be<br>changed on the fly<\/td><td>Deleter (removing attributes <br>dynamically by <code>del<\/code>)<\/td><\/tr><tr><td><\/td><td>Overloading<br>(Dispatch function by signature)<\/td><td><\/td><td>Overloading<\/td><td>Overload only by <br>first argument<\/td><td><code>@overload<\/code> (Static type) <code><br>@singledispath<br>@multipledispatch<\/code><\/td><\/tr><tr><td><\/td><td>Initializing class variables<\/td><td><\/td><td>Initializer Lists<br>Constructor<\/td><td>Constructor<\/td><td>Constructor<\/td><\/tr><tr><td><\/td><td>Constructor<\/td><td><\/td><td><code>ClassName()<\/code><br>Does not return<br>(<code>*this<\/code> is implicit)<\/td><td><code>obj=ClassName(...)<\/code><br>MUST output the constructed object<\/td><td><code>__init__(self, ...)<\/code><br>Object to be constructed is 1st argument<\/td><\/tr><tr><td><\/td><td>Destructor<\/td><td><\/td><td><code>~ClassName()<\/code><\/td><td><code>delete()<\/code><\/td><td><code>__del__()<\/code><\/td><\/tr><tr><td><\/td><td>Special<br>methods<\/td><td><\/td><td>Special member functions<\/td><td>(no name)<br><a href=\"https:\/\/www.mathworks.com\/help\/matlab\/matlab_oop\/methods-that-modify-default-behavior.html\">method that control specific behaviors<\/a><\/td><td>Magic\/Dunder methods<\/td><\/tr><tr><td><\/td><td>Operator overloading<\/td><td><\/td><td><code>operator<\/code><\/td><td><a href=\"https:\/\/www.mathworks.com\/help\/matlab\/matlab_oop\/implementing-operators-for-your-class.html\">operator methods to define<\/a><\/td><td><a href=\"https:\/\/www.pythonmorsels.com\/every-dunder-method\/\">Dunder methods<\/a><\/td><\/tr><tr><td><\/td><td>Resource<br>Self-cleanup<\/td><td><\/td><td>RIAA<\/td><td><code>onCleanup()<\/code>: make a dummy object with cleanup operation as destructor to be removed when it goes out of scope<\/td><td><code>with<\/code> Context Managers<\/td><\/tr><tr><td><\/td><td>Naming for the object itself<\/td><td><\/td><td>Class: (class&#8217;s own name by SRO <code>::<\/code>) <br>Instance: <code>*this<\/code><\/td><td>Class: (class&#8217;s own name)<br>Instance: <code>obj<\/code> (or any output name defined in constructor)<\/td><td>Class: <code>cls<\/code><br>Instance: <code>self<\/code><br>(Recommended PEP8 names)<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Python allows adding members (attributes) on the fly with <code>setattr()<\/code>, which includes methods. MATLAB&#8217;s dynamicprops allows adding properties (data members) on the fly with addprop<br><br><code>onCleanup()<\/code> does not work reliably on Python because MATLAB&#8217;s object destructor time is deterministic (MATLAB specifically do not garbage collect user objects to avoid this mess. It only garbage collects PODs) while Python leaves it up to garbage collector.<br><br><code>*this<\/code> is implicitly passed in C++ and not spelled out in the method declaration. The self object must be the first argument in the instance method&#8217;s signature\/prototype for both MATLAB and Python. <\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Functional Programming Constructs<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><\/td><td>Common<\/td><td><\/td><td>C++<\/td><td>MATLAB<\/td><td>Python<\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><td><\/td><td><\/td><td><\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><td><\/td><td><\/td><td><\/td><\/tr><tr><td><\/td><td>Function as<br>variable<\/td><td><\/td><td>Functors <br>(Function Objects)<br><code>operator()<\/code><\/td><td>Function Handle<\/td><td>Callables <br>(Function Objects)<br><code>__call__()<\/code><\/td><\/tr><tr><td><\/td><td>Lambda<br>Syntax<\/td><td><\/td><td>Lambda<br><code>[capture](inputs) {expr} -&gt; optional trailing return type<\/code><\/td><td>Anonymous Function<br><code>@(inputs) expr<\/code><\/td><td>Lambda<br><code>lambda inputs: expr<\/code><\/td><\/tr><tr><td><\/td><td><a href=\"https:\/\/wonghoi.humgar.com\/blog\/2021\/10\/28\/dart-language-late-binding-in-lambda-no-capture-syntax\/\" data-type=\"link\" data-id=\"https:\/\/wonghoi.humgar.com\/blog\/2021\/10\/28\/dart-language-late-binding-in-lambda-no-capture-syntax\/\">Closure<\/a><br>(Early binding): an <br>instance of function objects<\/td><td><\/td><td>Capture <code>[]<\/code> only as necessary.<br><br>Early binding <code>[=]<\/code> is capture all.<\/td><td>Early binding ONLY for anonymous functions (lambda).<br><br>Late binding for function handles to loose or <a href=\"https:\/\/research.wmz.ninja\/articles\/2017\/05\/closures-in-matlab.html\">nested functions<\/a>.<\/td><td>Late binding* by default, even for Lambdas. <br><br>Can capture <code>Po<\/code> through default values<br><code>lambda x,P=Po: x+P<\/code><br>(We&#8217;re relying users to not enter the captured\/optional input argument)<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Concepts of Early\/Late Binding also apply to non-lambda functions. It&#8217;s about when to access (usually read) the &#8216;global&#8217; or broader scope (such as during nested functions) variables that gets recruited as a non-input variable that&#8217;s local to the function itself. <br><br>An instance of a function object is not a closure if there&#8217;s any parameter that&#8217;s late bound. All lambdas (anonymous functions) in MATLAB are early bound (at creation).<br><br>The more proper way (<a href=\"https:\/\/medium.com\/skiller-whale\/late-binding-variables-its-a-trap-c17af980164f\">without creating an extra optional argument that&#8217;s not supposed to be used<\/a>, aka defaults overridden) to convert late binding to early binding (by capturing variables) is called <a href=\"https:\/\/docs.python.org\/3\/library\/functools.html#functools.partial\">partial application<\/a>, where you freeze the parameters (to be captured) by making them inputs to an outer layer function and return a function object (could be lambda) that uses these parameters. <br><br>The same trick (partial application) applies to bind (capture) variables in simple\/nested function handles in MATLAB which do behave the same way (early binding) like anonymous functions (lambda).<br><br>Currying is partial application one parameter at a time, which is tedious way to stay faithful to <strong>pure<\/strong> functional programming.<\/figcaption><\/figure>\n\n\n\n<p>List comprehension is a shorthand syntax for transform\/map() and copy_if\/remove_if\/filter() in one shot, but not accumulate\/reduce(). MATLAB and C\/C++ does not have listcomp, but listcomp is not specific to Python. Even Powershell has it.<\/p>\n\n\n\n<p>Listcomp syntax, if wrapped in round brackets like <code>(x**x for x in range(5))<\/code>, gives a generator. Wrapping in square bracket is the shortcut of casting the generator into a list, so <code>[x**x for x in range(5)]<\/code> is the same as <code>list(x**x for x in range(5))<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Coroutines \/ Asynchronous Programming<\/h2>\n\n\n\n<p>MATLAB natively does not support coroutines. <\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>Common<\/td><td>C++20<\/td><td><a href=\"https:\/\/www.integralist.co.uk\/posts\/python-generators\/\">Python<\/a><\/td><\/tr><tr><td>Generators<\/td><td>Input Iterators<\/td><td>Functions that <code>yield value_to_spit_out_on_next<\/code>  <br>(Implicitly return a generator\/functor with <code>iter<\/code> and <code>next<\/code>)<\/td><\/tr><tr><td>Coroutines<\/td><td><\/td><td>Functions that <code>value_accepted_from_outside = yield<\/code><br>Send value to the continuation by <code>g.send(user_input)<\/code><br><br><code>async<\/code>\/<code>await <\/code>(native coroutines)<\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Matrix Arrays<\/h2>\n\n\n\n<p>The way Numpy requires users to specify matrices with a bracket for every row drives me nuts. Not only there&#8217;s a lot of typing, the superfulous brackets reinforce C&#8217;s idea of row-major which is horrendous to people with a proper math background who see matrices as column-major <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/ql-cache\/quicklatex.com-e734dae46672ea55c4c9abf3ae844abb_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#65;&#125;&#95;&#123;&#114;&#44;&#99;&#125;\" title=\"Rendered by QuickLaTeX.com\" height=\"18\" width=\"31\" style=\"vertical-align: -6px;\"\/>. Pytorch is the same.<\/p>\n\n\n\n<p>Once you are trained in APL\/MATLAB&#8217;s matrix world-view, you&#8217;ll discover going back to the world where matrices aren&#8217;t first class citizens is clumsy AF. <\/p>\n\n\n\n<p>With Python, you lose the clutter free readability where your MATLAB code is one step away from the matrix equations in your scientific computing work, despite a lot of the features that addresses frequent use patterns are implemented earlier in Python than MATLAB. <\/p>\n\n\n\n<p>Don&#8217;t believe those who haven&#8217;t lived and breathed MATLAB tell you Python is strictly superior. No it isn&#8217;t. They just didn&#8217;t know what they were missing as they haven&#8217;t made the intellectual leap in MATLAB yet. Python is very convenient as a swiss-army knife but scientific computing is an afterthought in Python&#8217;s language design.<\/p>\n\n\n\n<p>The only way to use MATLAB-like semi-colon to change rows only works for np.matrix() type, which they plan to deprecate. For now one can cast matrix into array like <code>np.array(np.matrix(matrix_string))<\/code>.<\/p>\n\n\n\n<p>Even numpy&#8217;s ndarray (or matrix to be deprecated) are CONCEPTUALLY equivalent to a matrix of cells in MATLAB. There isn&#8217;t native numerical matrices like in MATLAB that doesn&#8217;t have the overhead of unpacking arbitrary data types. You don&#8217;t want to do numerical matrices in MATLAB with cell matrices as it&#8217;s insanely slow. <\/p>\n\n\n\n<p>You get away without the unpacking penalty in Numpy if all the contents of the ndarray happens to have the same <code><a href=\"https:\/\/numpy.org\/doc\/2.1\/reference\/arrays.dtypes.html\">dtype<\/a><\/code> (such as numerical), aka known to be uniform. In other words, MATLAB&#8217;s matrices are uniform if it&#8217;s formed by <code>[]<\/code> and heterogeneous if formed by <code>{}<\/code>, while for Python <code>[]<\/code> is context-dependent, kept track of by <code>dtype<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>Concept<\/strong><\/td><td><strong>MATLAB<\/strong><\/td><td><strong>Numpy<\/strong><\/td><\/tr><tr><td>Construction<\/td><td><code>[8,9;6,4]<\/code><\/td><td><code>np.array([[8,9],[6,4]])<\/code><\/td><\/tr><tr><td>Size by dimension<\/td><td><code>size()<\/code><\/td><td><code>A.shape<\/code><\/td><\/tr><tr><td>Concatenate<br>within existing dimensions<\/td><td><code>[A;B]<\/code> or <code>vertcat()<\/code><br><code>[A,B]<\/code> or <code>horzcat()<\/code><br><code>cat(dim, A, B, ...)<\/code><\/td><td><code>np.vstack()<\/code><br><code>np.hstack()<\/code><br><code>np.concatenate(list, dim)<\/code><\/td><\/tr><tr><td>Concatenate expanding<br>to 3D (expand in last dimension)<\/td><td><code>cat(3, A, B, ...)<\/code><\/td><td><code>np.dstack()<\/code><br>&#8216;d&#8217; for depth (3rd dimension)<\/td><\/tr><tr><td>Concatenate<br>expanding dimensions<\/td><td><code>cat(newdim, A, B, ...)<\/code> <br>then <code>permute()<\/code><\/td><td><code>np.stack([A, ..], expand_at_axis)<\/code> <br><code>np.array([A, ..])<\/code> expands at first <br>dimension as outermost bracket <br>refers to first dimension<\/td><\/tr><tr><td>Tiling<\/td><td><code>repmat()<\/code><\/td><td><code>np.tile()<\/code><\/td><\/tr><tr><td>Fill with same value<\/td><td><code>repmat()<\/code><\/td><td><code>np.full()<\/code><\/td><\/tr><tr><td>Fill with ones\/zeros<\/td><td><code>ones(), zeros()<\/code><\/td><td><code>np.ones(), np.zeros()<\/code><\/td><\/tr><tr><td>Fill minicking another<br>array&#8217;s size<\/td><td><code>repmat(x, size(B))<br>ones(x, size(B))<\/code><br><code>zeros(x, size(B))<\/code><\/td><td><code>np.full_like(B, x)<\/code><br><code>np.ones_like(B)<\/code><br><code>np.zeros_like(B)<\/code><\/td><\/tr><tr><td>Preallocate<\/td><td>Any of the above<br>(Must be initialized)<\/td><td><code>np.empty()<\/code><br><code>np.empty_like()<\/code><br>UNINITIALIZED<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\"><code>repelem()<\/code> is just <code>repmat()<\/code> with the repetition by axes vector expanded out as variable input arguments one per dimension. Using ones vector to broadcast a singleton instead of repmat() is horrendously inefficient and non-intuitive. <\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Heterogeneous Data Structures<\/h2>\n\n\n\n<p>Heterogeneous Data Structures are typically column major as it is a concept that derives from Structs of Arrays (SoA) and people typically expect columns to have the same data type from spreadsheets.<\/p>\n\n\n\n<p>While Pandas offers a lot of useful features that I&#8217;ve easily implemented with wrappers in MATLAB, the indexing syntax of Pandas\/Python is awkward and confusing. It&#8217;s due to the nature that matrix is a first-class citizen in MATLAB while it&#8217;s an afterthought in Python.<\/p>\n\n\n\n<p>Python does not have the <code>{ }<\/code> cell pack\/unpack operator in MATLAB, so in Pandas, you select the <code>Series<\/code> object (think of it as a <a href=\"https:\/\/medium.com\/@chinnarinarashimha\/a-more-to-know-about-pandas-series-and-a-small-chunk-of-python-lists-a0e8f3faa1d3#:~:text=Pandas%20series%20supports%20operations%20on,based%20and%20label%20based%20indexing.\">supercharged <code>list<\/code> with conveniences<\/a> such as handling missing values and keeping track of row\/column labels) then call its <code>.values<\/code> attribute.<\/p>\n\n\n\n<p>However, Pandas is a lot more advanced than MATLAB in terms of using multiple columns as keys and have more tools to exploit multi-key row names (row names not mandatory in MATLAB but mandatory in Pandas). In the old days I had to write my own MATLAB function with <code>unique(.., 'rows')<\/code> exploit its index output to build unique keys under the hood.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>Concept<\/td><td>MATLAB<\/td><td>Python (Pandas <br>Dataframe)<\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><\/tr><tr><td>Rows<\/td><td>Observations (<code>dataset()<\/code>)<br>Row (<code>table()<\/code>)<\/td><td>Rows<br>index<\/td><\/tr><tr><td>Columns<\/td><td>Variables<\/td><td>Columns<\/td><\/tr><tr><td>Select rows\/columns<\/td><td><code>T(rows, cols)<\/code><\/td><td><code>T.loc[r, col_name]<\/code><br><code>T.iloc[r,c]<\/code><br><br>Caveats: <br><br>&#8211; single index<br>(not wrapped in list)<br>have content extracted<br><br>&#8211; <code>iloc<\/code> on LHS cannot <br>expand table but <code>loc<\/code> can, but it can only inject 1 row<br><br>&#8211; can get index number of names by <code>T.get_loc()<\/code> to use with <code>T.iloc[]<\/code><\/td><\/tr><tr><td>Remove rows\/columns<\/td><td><code>T(rows, cols) = []<\/code><\/td><td><code>T.drop(index=rows, columns=cols)<\/code><br>Optionally: <code>inplace=True<\/code> <br><code>del T[rows, cols]<\/code> does NOT work<\/td><\/tr><tr><td>Extract one column<\/td><td><code>T{:, c}<\/code><\/td><td><code>T[c].values<\/code><\/td><\/tr><tr><td>Extract one entry<\/td><td><code>T{r, c}<\/code><\/td><td><code>T.at[r,col_name]<\/code><br><code>T.iat[r,c]<\/code><br><br>Faster than <code>loc\/iloc<\/code><\/td><\/tr><tr><td>Show first few rows<\/td><td><code>T(1:5, :)<\/code><\/td><td><code>T.head()<\/code><\/td><\/tr><tr><td>Drop duplicate rows<\/td><td><code>unique(T, 'stable')<\/code><\/td><td><code>T.drop_duplicates()<\/code><\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><\/tr><tr><td>Ordinal<\/td><td><code>categorical()<\/code><br><code>ordinal()<\/code> <\/td><td><code>Categorical()<\/code><br><code>Index()<\/code><\/td><\/tr><tr><td>Getting column names\/labels<\/td><td><code>T.Properties.VariableNames<\/code><br>(returns <code>cellstr()<\/code> only)<\/td><td><code>T.columns<\/code><br>(returns <code>Index()<\/code> or <code>RangeIndex()<\/code>)<\/td><\/tr><tr><td>Getting row<br>names\/labels<\/td><td><code>T.Properties.RowNames<\/code><\/td><td><code>T.index<\/code><\/td><\/tr><tr><td>Transpose table<\/td><td><code>rows2vars()<\/code><\/td><td><code>T.transpose()<\/code><\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><\/tr><tr><td>Move columns<br>by name<\/td><td><code>movevars()<\/code> since R2023a<\/td><td><\/td><\/tr><tr><td>Rename columns<\/td><td><code>renamevars()<\/code> since R2020a<\/td><td><code>T.rename(<strong>columns<\/strong>={source:target})<\/code><\/td><\/tr><tr><td>Rename rows<\/td><td>Modify<br><code>T.Properties.RowNames<\/code><\/td><td><code>T.rename(<strong>index<\/strong>={source:target})<\/code><\/td><\/tr><tr><td>Use column as row indices<\/td><td><code>T.Properties.RowNames<\/code> = <code>T.cellstr_variablename<\/code><br>If multiple columns are needed, need to combine them into one column using some user rules<\/td><td><code>T.set_index(column_to_use)<\/code><br>Dataframe allows multiple columns as row index keys<\/td><\/tr><tr><td>Reorder or partial selection<\/td><td><code>T[rows, cols]<\/code><\/td><td><code>T.reindex(<strong>columns<\/strong>=..., <strong>index<\/strong>=...)<\/code><br>New labels will autofill by <code>NaN<\/code><\/td><\/tr><tr><td>Select columns<\/td><td><code>T[:, cols]<\/code><\/td><td><code>T[list_of_cols]<\/code><\/td><\/tr><tr><td>Pick column by data type<\/td><td>T[:, <code>varfun(...)]<\/code><\/td><td><code>T.select_dtypes(include=[list of type names])<\/code><\/td><\/tr><tr><td>Pick column by string match<\/td><td>T[:, <code>varfun(...)]<\/code><\/td><td><code>T.filter(like=str_to_match)<\/code><\/td><\/tr><tr><td>Blindly concatenate columns of 2 tables<\/td><td><code>[T1, T2]<\/code><br><br>If you defined optional rownames, they must match. You can delete it with <code>T.Properties.RowNames = {}<\/code><\/td><td>Pandas assign row indices (labels) by default.<br><br>Mismatched row labels do not combine in the same row. Consider <code>reset_index()<\/code> or overwrite the row indices of one table with another, like <br><code>pd.concat([T1, T2.set_index(T1.index)]<\/code><\/td><\/tr><tr><td>Blindly<br>concatenate rows of 2 tables<\/td><td><code>[T1; T2]<\/code><\/td><td><code>pd.concat([T1, T2], ignore_index=True)<\/code><\/td><\/tr><tr><td><\/td><td><\/td><td><\/td><\/tr><tr><td>Format export<\/td><td><code>writetable()<\/code><\/td><td><code>.to_*()<\/code><\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">MATLAB tables does not support ranging through column names (such as <code>'apple':'grapes'<\/code>) yet Pandas DataFrame support it. I don&#8217;t think it&#8217;s fine to use it in the interpreter to poke around, but this is just asking for confusing logic bugs when the columns are moved around and the programmer has a false sense of security knowing exactly what&#8217;s where because they are using only names.<br><br>Dataframe is a little smarter than MATLAB&#8217;s table() in terms of managing column names and indices as it&#8217;s tracked with <code>Index()<\/code> type which is the same idea as MATLAB&#8217;s <code>ordinal()<\/code> ordered categorical type, where uniques names are mapped to unique indices and it&#8217;s the indices under the hood. This is how <code>'apple':'grapes'<\/code> can work in Python but not MATLAB.<br><br>MATLAB <code>T.Properties.VariableNames<\/code> is a little clumsy. I usually implement a consistent interface called <code>varnames()<\/code> that&#8217;d output the same <code>cellstr()<\/code> headings whether it&#8217;s struct, dataset or table objects.<br><br>MATLAB&#8217;s <code>table()<\/code> by default do not make up row names. Pandas make up row names by default sequentially.<br><br>MATLAB <code>table()<\/code> do requires qualified string characters as variable names. Dataframe doesn&#8217;t care what labels you use as long as <code>Index()<\/code> takes it. It can get confusing because you can have a number 1 and &#8216;1&#8217; as column headers at the same time and they look the same when displayed in the console.<\/figcaption><\/figure>\n\n\n\n<p>&#8221;<\/p>\n\n\n\n<p><\/p>\n<div class=\"pvc_clear\"><\/div><p id=\"pvc_stats_5941\" class=\"pvc_stats all  \" data-element-id=\"5941\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p><div class=\"pvc_clear\"><\/div>","protected":false},"excerpt":{"rendered":"<p>Common C C++ MATLAB Python Variable arguments &lt;stdarg.h&gt;T f(&#8230;) Packed in va_arg Very BAD! Cannot overloadwhen signatures are uncertain. vararginvarargout Both packed as cells. MATLAB does not have named arguments *args (simple, stored as tuples) **kwargs (specify input by keyword, &hellip; <a href=\"https:\/\/wonghoi.humgar.com\/blog\/2025\/02\/19\/dictionary-of-equivalent-analogous-concepts-in-programming-languages\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_5941\" class=\"pvc_stats all  \" data-element-id=\"5941\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[30,25,59,61,10,34],"tags":[],"class_list":["post-5941","post","type-post","status-publish","format-standard","hentry","category-c-programming","category-cpp","category-concepts","category-functional-programming","category-matlab","category-python"],"_links":{"self":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/5941","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/comments?post=5941"}],"version-history":[{"count":139,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/5941\/revisions"}],"predecessor-version":[{"id":6534,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/5941\/revisions\/6534"}],"wp:attachment":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/media?parent=5941"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/categories?post=5941"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/tags?post=5941"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}