Article 2PRZD Bring Your Own Code: Your Private Foursome

Bring Your Own Code: Your Private Foursome

by
Remy Porter
from The Daily WTF on (#2PRZD)

Last week, I shared some code that, while imperfect, wasn't that bad. I then issued a challenge: make it worse. Or better, if you really want. As many comments noted: one case covers only the first iteration of the loop, and one case only covers the last iteration of the loop. You could easily pull those out of the loop, and not need a for-case at all. Others noticed that this pattern looked like odd slices out of an identity matrix.

With that in mind, we got a few numpy, Matlab, or MatrixUtils based solutions generally were the "best" solutions to the problem: generate an identity matrix and take slices out of it. This is reasonable and fine. It makes perfect sense. Let's see if we can avoid making sense.

I'll start with Abner Qian's Ruby solution.

module MagicalArrayGenerator def magical_array_generator main_array = [] self.times do |i| inner_array = [] self.times do |j| i == j ? inner_array << 1 : inner_array << 0 end main_array << inner_array end e_1 = [] n_1 = [] e_n = [] n_n = [] self.times do |i| e_1 << [main_array[i].first] e_n << [main_array[i].last] n_1 << main_array[i][1..-1] n_n << main_array[i][0..-2] end [e_1, n_1, e_n, n_n] endendclass Integer include MagicalArrayGeneratorende_1, n_1, e_n, n_n = 4.magical_array_generator

At it's core, this is simply an implementation that generates an identity matrix and slices it up. The actual implementation, however, is a pitch-perfect parody of Ruby development: "There's no problem that can't be solved by monkey-patching a method into a built-in type". That's what happens here- the include statment injects this method into the build-in Integer data-type, meaning you can call 4.magical_array_generator and get your arrays. Abner also points out that Ruby uses 62-bit integers, just in case you want some 4611686018427387903 by 4611686018427387904 arrays.

Several folks looked at the idea of taking slices, and said, "Gee, I bet you I could do this with pointers in C". My personal favorite in that category would have to be Ron P's approach.

#include <stdio.h>int main( int argc, char **argv){ int *e_1 = 0; int *e_n = 0; int **n_1 = 0; int **n_n = 0; int *fugly = 0; int i,j; if ( argc != 2 ) return 1; int n = atoi(argv[1]); fugly = calloc( n*(n+1),sizeof(int)); n_1 = calloc(n,sizeof(int *)); n_n = calloc(n,sizeof(int *)); for ( i = 0, j=n; i < n; ++i, j+=n+1 ) { fugly[j]=1; n_1[i]=fugly+n*i; n_n[i]=n_1[i]+n; } e_1 = fugly+n; e_n = fugly+1; printf( "e_1\n" ); for ( i = 0; i < n; ++i ) { printf( " %d\n", e_1[i]); } printf( "\ne_n\n" ); for ( i = 0; i < n; ++i ) { printf( " %d\n", e_n[i]); } printf( "\nn_1\n" ); for ( i = 0; i < n; ++i ) { printf( " " ); for ( j = 0; j < n-1; ++j ) { printf("%d ", n_1[i][j]); } printf("\n" ); } printf( "\nn_n\n" ); for ( i = 0; i < n; ++i ) { printf( " " ); for ( j = 0; j < n-1; ++j ) { printf("%d ", n_n[i][j]); } printf("\n" ); } return 0;}

Now, Martin Scolding gets bonus points for two reasons: first, he uses one of the worst languages in the world (not designed as an esolang), and second, this language doesn't technically support multi-dimensional arrays. I speak, of course, of PL/SQL. Note the use of substrings to figure out what number to put in each position of the array.

DECLARE TYPE data_t IS TABLE OF INTEGER INDEX BY PLS_INTEGER; TYPE array_t IS TABLE OF data_t INDEX BY PLS_INTEGER; e_1 array_t; e_n array_t; n_1 array_t; n_n array_t; l_array_size INTEGER := 0;PROCEDURE gen_arrays(n INTEGER, p_e_1 IN OUT array_t, p_e_n IN OUT array_t, p_n_1 IN OUT array_t, p_n_n IN OUT array_t)--' Generate 4 Arrays of the form (example n=4)---- ' | 1 | | 0 0 0 |-- ' e_1 = | 0 | n_1 = | 1 0 0 |-- ' | 0 | | 0 1 0 |-- ' | 0 | | 0 0 1 |-- '-- ' | 0 | | 1 0 0 |-- ' e_n = | 0 | n_n = | 0 1 0 |-- ' | 0 | | 0 0 1 |-- ' | 1 | | 0 0 0 |--IS l_n_string LONG := RPAD('1',n+1,'0');BEGIN For i in 1..n Loop p_e_1(i)(1) := TO_NUMBER(SUBSTR(l_n_string, 1, 1)); p_e_n(i)(1) := TO_NUMBER(SUBSTR(l_n_string, n, 1)); For j in 1..n-1 Loop p_n_1(i)(j) := TO_NUMBER(SUBSTR(l_n_string, j+1, 1)); p_n_n(i)(j) := TO_NUMBER(SUBSTR(l_n_string, j, 1)); End Loop; l_n_string := LPAD(SUBSTR(l_n_string, 1, n), n+1, '0'); End Loop;END;BEGIN l_array_size := &inp_array; gen_arrays(l_array_size, e_1, e_n, n_1, n_n); --========================================================================== -- DISPLAY RESULTS --========================================================================== DBMS_OUTPUT.PUT_LINE('e_1 = '); For i in 1..l_array_size Loop DBMS_OUTPUT.PUT_LINE(' | ' || e_1(i)(1) || ' |'); End Loop; DBMS_OUTPUT.PUT_LINE('--------------------------------------------------'); DBMS_OUTPUT.PUT_LINE('e_n = '); For i in 1..l_array_size Loop DBMS_OUTPUT.PUT_LINE(' | ' || e_n(i)(1) || ' |'); End Loop; DBMS_OUTPUT.PUT_LINE('--------------------------------------------------'); DBMS_OUTPUT.PUT_LINE('n_1 = '); For i in 1..l_array_size Loop DBMS_OUTPUT.PUT(' | '); For j in 1..l_array_size-1 Loop DBMS_OUTPUT.PUT(n_1(i)(j) || ' '); End Loop; DBMS_OUTPUT.PUT('|'); DBMS_OUTPUT.NEW_LINE; End Loop; DBMS_OUTPUT.PUT_LINE('--------------------------------------------------'); DBMS_OUTPUT.PUT_LINE('n_n = '); For i in 1..l_array_size Loop DBMS_OUTPUT.PUT(' | '); For j in 1..l_array_size-1 Loop DBMS_OUTPUT.PUT(n_n(i)(j) || ' '); End Loop; DBMS_OUTPUT.PUT('|'); DBMS_OUTPUT.NEW_LINE; End Loop; DBMS_OUTPUT.PUT_LINE('--------------------------------------------------'); --========================================================================== -- --==========================================================================END;/

Finally, though, I have to give a little space to Airdrik. While the code may contain some errors, it is in Visual Basic, as was the original solution, and it knows that recursion makes everything better.

Public Sub GenerateIdentitySquare(ByVal n As Long, ByRef sq As Variant, ByVal i As Long, ByVal j As Long) Select Case j Case i: sq(i, j) = #1 If i < n Then GenerateIdentitySquare(n, sq, i, j+1) End If Case n: sq(i, j) = #0 GenerateIdentitySquare(n, sq, i+1, 1) Case Else: sq(i, j) = #0 GenerateIdentitySquare(n, sq, i, j+1) End SelectEnd SubPublic Sub CopyRowValues(ByVal n As Long, ByRef sq As Variant, ByRef e As Variant, ByVal sq_i As Long, ByVal e_i As Long, ByVal j As Long) e(e_i, j) = sq(sq_i, j) if j < n Then CopyRowValues(n, sq, e, sq_i, e_i, j+1) End IfEnd SubPublic Sub CopyRows(ByVal n As Long, ByRef sq As Variant, ByRef e_1 As Variant, ByRef e_n As Variant, ByRef n_1 As Variant, ByRef n_n As Variant, ByVal i As Long) Select Case i Case 1: CopyRowValues(n, sq, e_1, i, 1, 1) CopyRowValues(n, sq, n_n, i, i, 1) CopyRows(n, sq, e_1, e_n, n_1, n_n, i+1) Case n: CopyRowValues(n, sq, n_1, i, i-1, 1) CopyRowValues(n, sq, n_n, i, i, 1) Case Else: CopyRowValues(n, sq, n_1, i, i-1, 1) CopyRowValues(n, sq, e_n, i, 1, 1) CopyRows(n, sq, e_1, e_n, n_1, n_n, i+1) End SelectEnd SubPublic Sub DefineProjectionArrays(ByVal n As Long, ByRef e_1 As Variant, ByRef e_n As Variant, ByRef n_1 As Variant, ByRef n_n As Variant) Dim i As Long, j As Long ' Generate 4 Arrays of the form (example n=4) ' | 1 | | 0 0 0 | ' e_1 = | 0 | n_1 = | 1 0 0 | ' | 0 | | 0 1 0 | ' | 0 | | 0 0 1 | ' ' | 0 | | 1 0 0 | ' e_n = | 0 | n_n = | 0 1 0 | ' | 0 | | 0 0 1 | ' | 1 | | 0 0 0 | Dim sq(n, n) As Variant GenerateIdentitySquare(n, sq, 1, 1) ReDim e_1(n, 1) ReDim e_n(n, 1) ReDim n_1(n, n - 1) ReDim n_n(n, n - 1) CopyRows(n, sq, e_1, e_n, n_1, n_n, 1)End Sub

Functional programming is always the best approach, obviously.

release50.png[Advertisement] Release!is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped! TheDailyWtf?d=yIl2AUoC8zA8mZZIWZkocs
External Content
Source RSS or Atom Feed
Feed Location http://syndication.thedailywtf.com/TheDailyWtf
Feed Title The Daily WTF
Feed Link http://thedailywtf.com/
Reply 0 comments